home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr44 / 2m30src.zip / 2M-ABIOS.ASM next >
Assembly Source File  |  1995-03-06  |  134KB  |  3,216 lines

  1.  
  2. ;┌───────────────────────────────────────────────────────────────────┐
  3. ;│                                                                   │
  4. ;│           █████ █   █       █▀▀▀█ █▀▀▄  ▀▀█▀▀ ▄▀▀▀▄ █▀▀▀▀         │
  5. ;│               █ ██ ██       █   █ █   █   █   █   █ █             │
  6. ;│           █████ █ █ █ ▀▀▀▀▀ █████ ████    █   █   █ █████         │
  7. ;│           █     █   █       █   █ █   █   █   █   █     █         │
  8. ;│           █████ █   █       █   █ █▄▄▀  ▄▄█▄▄ ▀▄▄▄▀ █████         │
  9. ;│                                                                   │
  10. ;│                                                                   │
  11. ;│      2M-ABIOS 1.3  -  (C) 1994-1995 Ciriaco García de Celis.      │
  12. ;│                                                                   │
  13. ;│          Código para emular al 100% la BIOS AMI de 1993.          │
  14. ;│                                                                   │
  15. ;│     Si  el  ordenador posee disco duro y una BIOS moderna, la     │
  16. ;│     INT 40h  controla  los  accesos a disquete.  Desviar esta     │
  17. ;│     interrupción  en  lugar  de  la  INT 13h permite que este     │
  18. ;│     programa  tome  el  control  de las disqueteras antes que     │
  19. ;│     cualquier  otro  (incluso  aunque  se  instale después) y     │
  20. ;│     además  permite  seguir trabajando al código del DOS que,     │
  21. ;│     desde  INT 13h,  soluciona  el cruce con las fronteras de     │
  22. ;│     DMA antes de invocar a la INT 40h.                            │
  23. ;│                                                                   │
  24. ;│     Si el ordenador no utilizase la  INT 40h en los accesos a     │
  25. ;│     las disqueteras se desvía INT 13h y se cuelga este código     │
  26. ;│     de la misma, cuidando evitar un cruce con el DMA a través     │
  27. ;│     de un buffer intermedio auxiliar si es preciso.               │
  28. ;│                                                                   │
  29. ;│     Para la versión AT:     Para la versión PC/XT:                │
  30. ;│       TASM  2m-abios /m5      TASM  2m-abios, 2m-xbios /m5 /dXT   │
  31. ;│       TLINK 2m-abios          TLINK 2m-xbios                      │
  32. ;│                                                                   │
  33. ;│     Con  [+]  se señalizan las líneas del listado que cambian     │
  34. ;│     de  manera  intencionada  y  por  algún  motivo  especial     │
  35. ;│     respecto a la BIOS AMI original (entre otras no señaladas     │
  36. ;│     por no tener un motivo tan especial de cambio).               │
  37. ;│                                                                   │
  38. ;└───────────────────────────────────────────────────────────────────┘
  39.  
  40.               IFDEF XT
  41.                ID EQU ,"X",
  42.               ELSE
  43.                .286                    ; versión para AT o superior
  44.                ID EQU ,"A",
  45.               ENDIF
  46.  
  47. ; ------------ Macros de propósito general.
  48.  
  49. XPUSH          MACRO regmem            ; apilar lista de registros
  50.                  IRP rm, <regmem>
  51.                    PUSH rm
  52.                  ENDM
  53.                ENDM
  54.  
  55. XPOP           MACRO regmem            ; desapilar lista de registros
  56.                  IRP rm, <regmem>
  57.                    POP rm
  58.                  ENDM
  59.                ENDM
  60.  
  61.               IFNDEF XT
  62.  
  63. XPUSHA         MACRO
  64.                  PUSHA
  65.                ENDM
  66.  
  67. XPOPA          MACRO
  68.                  POPA
  69.                ENDM
  70.  
  71. XSHR           MACRO regmem, cuenta
  72.                  SHR regmem,cuenta
  73.                ENDM
  74.  
  75. XSHL           MACRO regmem, cuenta
  76.                  SHL regmem,cuenta
  77.                ENDM
  78.  
  79. XROR           MACRO regmem, cuenta
  80.                  ROR regmem,cuenta
  81.                ENDM
  82.  
  83. XROL           MACRO regmem, cuenta
  84.                  ROL regmem,cuenta
  85.                ENDM
  86.  
  87. DDS            MACRO
  88.                PUSH  40h
  89.                POP   DS
  90.                ENDM
  91.  
  92.               ELSE
  93.  
  94. XPUSHA         MACRO
  95.                  XPUSH <AX, BX, CX, DX, SI, DI>
  96.                ENDM
  97.  
  98. XPOPA          MACRO
  99.                  XPOP  <DI, SI, DX, CX, BX, AX>
  100.                ENDM
  101.  
  102. XSHR           MACRO regmem, cuenta
  103.                  REPT cuenta
  104.                    SHR regmem,1
  105.                  ENDM
  106.                ENDM
  107.  
  108. XSHL           MACRO regmem, cuenta
  109.                  REPT cuenta
  110.                    SHL regmem,1
  111.                  ENDM
  112.                ENDM
  113.  
  114. XROR           MACRO regmem, cuenta
  115.                  REPT cuenta
  116.                    ROR regmem,1
  117.                  ENDM
  118.                ENDM
  119.  
  120. XROL           MACRO regmem, cuenta
  121.                  REPT cuenta
  122.                    ROL regmem,1
  123.                  ENDM
  124.                ENDM
  125.  
  126. DDS            MACRO
  127.                PUSH  AX
  128.                MOV   AX,40h
  129.                MOV   DS,AX
  130.                POP   AX
  131.                ENDM
  132.  
  133.               ENDIF
  134.  
  135. ; ************ Inicio del área residente.
  136.  
  137. _PRINCIPAL     SEGMENT
  138.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  139.  
  140.                ORG   0
  141.  
  142. ini_residente  EQU   $
  143.  
  144.                DD    -1           ; encadenamiento con otros drivers
  145. tipo_drive     DW    8000h        ; palabra de atributo:
  146.                                   ; bit 15 a 1: dispositivo caracteres
  147.                                   ; bit 14 a 0: sin control IOCTL
  148.                DW    estrategia   ; rutina de estrategia
  149.                DW    interrupcion ; rutina de interrupción
  150.                DB    "2M-BIOS$"   ; nombre del dispositivo
  151.  
  152. estrategia     PROC  FAR
  153.                MOV   CS:pcab_pet_segm,ES
  154.                MOV   CS:pcab_pet_desp,BX
  155.                RET
  156. estrategia     ENDP
  157.  
  158. interrupcion   PROC  FAR
  159.                CALL  main  ; tras instalar: XPUSH <DS, BX> y MOV BX,??
  160. pcab_pet_segm  DW    ?
  161.                MOV   DS,BX
  162.                DB    0BBh  ; opcode de MOV BX,??
  163. pcab_pet_desp  DW    ?
  164.                MOV   WORD PTR [BX+3],8103h  ; código de error
  165.                XPOP  <BX, DS>
  166.                RET
  167. interrupcion   ENDP
  168.  
  169. ; ****************************************
  170. ; *                                      *
  171. ; *   D A T O S    R E S I D E N T E S   *
  172. ; *                                      *
  173. ; ****************************************
  174.  
  175. ; ------------ Identificación estandarizada del programa.
  176.  
  177. program_id     LABEL BYTE
  178. segmento_real  DW    0   ; segmento real donde será cargado
  179. offset_real    DW    0   ; offset real     "     "     "
  180. longitud_total DW    0   ; zona de memoria ocupada (párrafos)
  181. info_extra     DB    03h ; bits 0, 1 y 2-> 000: normal, con PSP
  182.                          ;                 001: bloque UMB XMS
  183.                          ;                 010: *.SYS
  184.                          ;                 011: *.SYS formato EXE
  185.                          ; bit 7 a 1: «extension_id» definida
  186. multiplex_id   DB    0   ; número Multiplex de este TSR
  187. vectores_id    DW    tabla_vectores
  188. extension_id   DW    0
  189.                DB    "*##*"
  190. autor_nom_ver  DB    "CiriSOFT:2M-" ID "BIOS:1.3",0
  191.  
  192.                DB    3  ; número de vectores de interrupción usados
  193. tabla_vectores EQU   $
  194.                DB    15h           ; INT 15h
  195. ant_int15      LABEL DWORD         ; dirección original
  196. ant_int15_off  DW    0
  197. ant_int15_seg  DW    0
  198.                DB    2Fh           ; INT 2Fh
  199. ant_int2F      LABEL DWORD         ; dirección original
  200. ant_int2F_off  DW    0
  201. ant_int2F_seg  DW    0
  202.                DB    40h           ; INT 40h
  203. ant_int40      LABEL DWORD         ; dirección original
  204. ant_int40_off  DW    0
  205. ant_int40_seg  DW    0
  206.                DB    13h           ; INT 13h podría llegar a usarse
  207. ant_int13      LABEL DWORD
  208. ant_int13_off  DW    0
  209. ant_int13_seg  DW    0
  210.  
  211. ; ***************************************
  212. ; *                                     *
  213. ; *   C O D I G O   R E S I D E N T E   *
  214. ; *                                     *
  215. ; ***************************************
  216.  
  217. ; ------------ Rutina de gestión de INT 2Fh.
  218.  
  219. ges_int2F      PROC  FAR
  220.                STI
  221.                CMP   AH,CS:multiplex_id
  222.                JE    preguntan
  223.                JMP   CS:ant_int2F      ; saltar al gestor de INT 2Fh
  224. preguntan:     CMP   DI,1992h
  225.                JNE   ret_no_info       ; no llama alguien del convenio
  226.                MOV   AX,ES
  227.                CMP   AX,1492h
  228.                JNE   ret_no_info       ; no llama alguien del convenio
  229.                PUSH  CS
  230.                POP   ES                ; sí llama: darle información
  231.                LEA   DI,autor_nom_ver
  232. ret_no_info:   MOV   AX,0FFFFh         ; "entrada multiplex en uso"
  233.                IRET
  234. ges_int2F      ENDP
  235.  
  236. ; ------------ Rutina de gestión de INT 15h.
  237.  
  238. ges_int15      PROC  FAR
  239.                STI
  240.                CMP   AX,90FDh
  241.                JE    ret_clc
  242.                CMP   AX,9001h
  243.                JE    ret_clc
  244.                JMP   CS:ant_int15
  245. ret_clc:       CLC
  246.                RET   2
  247. ges_int15      ENDP
  248.  
  249. ; ------------ Rutina de control de INT 40h.
  250.  
  251. r_flags        EQU   WORD PTR [BP+18h] ; constantes para parámetros
  252. r_flags_l      EQU   BYTE PTR [BP+18h]
  253. r_flags_h      EQU   BYTE PTR [BP+19h]
  254. r_ax           EQU   WORD PTR [BP+12h]
  255. r_al           EQU   BYTE PTR [BP+12h]
  256. r_ah           EQU   BYTE PTR [BP+13h]
  257. r_cx           EQU   WORD PTR [BP+10h]
  258. r_cl           EQU   BYTE PTR [BP+10h]
  259. r_ch           EQU   BYTE PTR [BP+11h]
  260. r_dx           EQU   WORD PTR [BP+0Eh]
  261. r_dl           EQU   BYTE PTR [BP+0Eh]
  262. r_dh           EQU   BYTE PTR [BP+0Fh]
  263. r_bx           EQU   WORD PTR [BP+0Ch]
  264. r_bl           EQU   BYTE PTR [BP+0Ch]
  265. r_bh           EQU   BYTE PTR [BP+0Dh]
  266. r_bp           EQU   WORD PTR [BP+0Ah]
  267. r_si           EQU   WORD PTR [BP+08h]
  268. r_di           EQU   WORD PTR [BP+06h]
  269. r_ds           EQU   WORD PTR [BP+04h]
  270. r_es           EQU   WORD PTR [BP+02h]
  271.  
  272. ges_int40      PROC
  273.                STI
  274.                CLD
  275.                PUSH  AX
  276.                PUSH  CX
  277.                PUSH  DX
  278.                PUSH  BX
  279.                PUSH  BP
  280.                PUSH  SI
  281.                PUSH  DI
  282.                PUSH  DS
  283.                PUSH  ES
  284.                PUSH  BP
  285.                MOV   BP,SP
  286.                DDS
  287.                PUSH  AX
  288.                MOV   AL,AH
  289.                CMP   AL,18h
  290.                JA    mal_funcion
  291.                CMP   AL,5
  292.                JBE   func_oper
  293.                CMP   AL,8
  294.                JNE   func_aux?
  295.                MOV   AL,6
  296.                JMP   func_oper
  297. func_aux?:     CMP   AL,15h
  298.                JB    mal_funcion
  299.                SUB   AL,0Eh
  300. func_oper:     CBW
  301.                MOV   DI,AX
  302.                POP   AX
  303.                SHL   DI,1
  304.                JMP   CS:tab_jmp[DI]    ; ejecutar función
  305. main_exit:     MOV   AL,AH             ; preservar resultado
  306.                LAHF                    ; preservar flags
  307.                PUSH  AX
  308.                DDS
  309.                MOV   AL,r_dl           ; DL a la llamada (unidad)
  310.                CMP   AL,1
  311.                JA    u_det             ; unidad incorrecta
  312.                XOR   AH,AH
  313.                MOV   BX,90h
  314.                ADD   BX,AX             ; [BX] -> estado físico unidad
  315.                TEST  BYTE PTR DS:[BX],10h  ; ¿densidad determinada?
  316.                JZ    u_det                 ; no
  317.                MOV   DL,4                  ; sí
  318.                MUL   DL
  319.                MOV   CL,AL
  320.                SHL   DL,CL
  321.                OR    DS:[8Fh],DL           ; unidad determinada
  322. u_det:         POP   AX
  323.                SAHF                    ; recuperar flags
  324.                MOV   AH,AL             ; recuperar resultado
  325. exit_i40:      MOV   r_ah,AH           ; AH para la salida del IRET
  326.                MOV   AX,201H           ; STI + STC en flags
  327.                JC    set_err           ; hay error
  328.                AND   r_flags_l,0FEH    ; CLC (si no hay error)
  329.                DEC   AX                ; dejar sólo STI
  330. set_err:       OR    r_flags,AX        ; flags a la salida del IRET
  331.                POP   BP
  332.                POP   ES
  333.                POP   DS
  334.                POP   DI
  335.                POP   SI
  336.                POP   BP
  337.                POP   BX
  338.                POP   DX
  339.                POP   CX
  340.                POP   AX                ; registros con resultado
  341.                IRET
  342. ges_int40      ENDP
  343.  
  344. mal_funcion:   POP   AX
  345.                MOV   AH,1              ; función/parámetro incorrecto
  346.                MOV   DS:[41h],AH       ; código de error
  347.                STC                     ; condición de error
  348.                JMP   exit_i40
  349.  
  350. ; ------------ Función 0: Resetear el sistema de disco.
  351.  
  352. reset          PROC
  353.                CALL  full_init         ; inicialización plena
  354.                MOV   DS:[41h],AH       ; código de error
  355.                MOV   AL,AH             ; preservar código
  356.                LAHF                    ; preservar flags
  357.                PUSH  AX
  358.                PUSH  DS
  359.                XOR   SI,SI
  360.                MOV   DS,SI
  361.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  362.                MOV   CL,[SI+2]
  363.                POP   DS
  364.                MOV   DS:[40h],CL       ; tics para detención motor
  365.                POP   AX
  366.                SAHF
  367.                MOV   AH,AL             ; restaurado código y flags
  368.                JMP   exit_i40
  369. reset          ENDP
  370.  
  371. ; ------------ Inicialización plena.
  372.  
  373. full_init      PROC
  374.                AND   BYTE PTR DS:[3Eh],0F0h   ; futuro recalibramiento
  375.                JMP   init_fdc                 ; inicializar FDC
  376. fdc_init:      JC    init_end
  377.                JMP   send_specify             ; enviar specify
  378. specify_sent:  JC    init_end
  379.                XOR   AH,AH                    ; no hay error
  380. init_end:      RET
  381. full_init      ENDP
  382.  
  383. ; ------------ Función 1: Obtener resultado de la última operación.
  384.  
  385. get_status     PROC
  386.                MOV   AH,DS:[41h]
  387.                OR    AH,AH
  388.                JZ    no_err
  389.                STC
  390. no_err:        JMP   exit_i40
  391. get_status     ENDP
  392.  
  393. ; ------------ Función 15h: Obtener el tipo de disco.
  394.  
  395. get_disk_type  PROC
  396.                CMP   DL,1
  397.                JBE   gdt_ok
  398.                MOV   AH,1              ; función/parámetro incorrecto
  399.                STC
  400.                MOV   DS:[41h],AH       ; código de error
  401.                JMP   gdt_exit
  402. gdt_ok:        MOV   BX,90h
  403.                XOR   DH,DH
  404.                ADD   BX,DX             ; [BX] -> estado físico unidad
  405.                MOV   BL,[BX]           ; estado físico de la unidad
  406.                OR    BL,BL
  407.                JNZ   gdt_posible
  408.                XOR   AH,AH             ; no existe tal unidad
  409.                JMP   gdt_bye
  410. gdt_posible:   AND   BL,7
  411.                JZ    gdt_without       ; 360K
  412.                CMP   BL,3
  413.                JE    gdt_without       ; 360K
  414.                CALL  get_drive_type    ; [+] Tipo disquetera en AL
  415.                CMP   AL,3              ; [+] sin soporte cambio en 720
  416.                JE    gdt_without       ; [+] Bug en BIOS AMI original?
  417.                MOV   AH,2
  418.                JMP   gdt_bye           ; con soporte cambio de línea
  419. gdt_without:   MOV   AH,1              ; sin soporte cambio de línea
  420. gdt_bye:       CLC
  421.                MOV   BYTE PTR DS:[41h],0  ; siempre sin error
  422. gdt_exit:      JMP   main_exit
  423. get_disk_type  ENDP
  424.  
  425. ; ------------ Función 17h: Establecer tipo de soporte para formateo.
  426.  
  427. set_type_fmt   PROC
  428.                XOR   AH,AH
  429.                CMP   DL,1
  430.                JBE   set_tp
  431. set_tp_bad_p:  MOV   AH,1              ; función/parámetro incorrecto
  432. set_tp_err:    MOV   DS:[41h],AH       ; código de error
  433.                STC
  434.                JMP   set_tp_exit
  435. set_tp:        CMP   AL,0              ; validar parámetro
  436.                JE    set_tp_bad_p
  437.                CMP   AL,4
  438.                JA    set_tp_bad_p
  439.                MOV   BX,90h
  440.                XOR   DH,DH
  441.                ADD   BX,DX             ; [BX] -> estado físico unidad
  442.                CMP   AL,1              ; ¿360K en 360K?
  443.                JNE   set_tp_n360
  444.                MOV   BYTE PTR DS:[BX],93h  ; actualizar variable tipo
  445.                MOV   BYTE PTR DS:[41h],0   ; anular errores previos
  446.                JMP   set_tp_t_exit
  447. set_tp_n360:   MOV   CX,AX
  448.                PUSH  BX
  449.                CALL  motor_on              ; arrancar motor
  450.                POP   SI
  451.                PUSH  SI
  452.                CALL  read_disk_chg         ; ¿cambio de disco?
  453.                POP   BX
  454.                CMP   AH,6                  ; (0: no, 6: sí)
  455.                JBE   set_tp_cd             ; haya cambio o no
  456.                CMP   AH,80h
  457.                JNE   set_tp_cd             ; sí existe disco
  458.                CMP   BYTE PTR DS:[BX],97h  ; ¿250 Kbps y no es 5.25?
  459.                JE    set_tp_err            ; error
  460.                MOV   BYTE PTR DS:[BX],61h  ; 300 Kbps, try 360 en 1.2
  461.                JMP   set_tp_err            ; error
  462. set_tp_cd:     CMP   CL,4                  ; ¿720K en 720K?
  463.                JNE   set_tp_n720           ; no
  464.                MOV   BYTE PTR DS:[BX],97h  ; actualizar variable tipo
  465.                JMP   set_tp_t_exit
  466. set_tp_n720:   CMP   CL,2                  ; ¿360K en 1.2M?
  467.                JNE   set_tp_ndd            ; no
  468.                MOV   BYTE PTR DS:[BX],74h  ; actualizar variable tipo
  469.                JMP   set_tp_t_exit
  470. set_tp_ndd:    MOV   BYTE PTR DS:[BX],15h  ; 1.2M en 1.2M
  471. set_tp_t_exit: OR    AH,AH                 ; comprobar posible error
  472.                JNZ   set_tp_err
  473.                MOV   BYTE PTR DS:[41h],0
  474. set_tp_exit:   JMP   main_exit
  475. set_type_fmt   ENDP
  476.  
  477. ; ------------ Función 16h: Detectar cambio de disco.
  478.  
  479. detect_change  PROC
  480.                CMP   DL,1
  481.                JBE   det_ch
  482.                MOV   AH,1              ; función/parámetro incorrecto
  483. det_ch_r_err:  STC
  484.                JMP   det_ch_end
  485. det_ch:        XOR   DH,DH
  486.                MOV   BX,90h
  487.                ADD   BX,DX               ; [BX] -> estado físico
  488.                CMP   BYTE PTR DS:[BX],0  ; ¿estado indeterminado?...
  489.                MOV   AH,80h              ; "unidad no preparada"
  490.                JE    det_ch_r_err        ; ...en efecto
  491.                MOV   AH,[BX]
  492.                AND   AH,7
  493.                JZ    det_ch_yes          ; 360K en 360K, no es posible
  494.                CMP   AH,3
  495.                JE    det_ch_yes          ; no es 360K en 360K
  496.                CALL  get_drive_type      ; [+] Tipo disquetera en AL
  497.                CMP   AL,3                ; [+] sin soporte cambio en 720
  498.                JNE   det_ch_calc         ; [+] Bug en BIOS AMI original?
  499. det_ch_yes:    MOV   AH,6                ; hay cambio (o desconocido)
  500.                STC
  501.                JMP   det_ch_end
  502. det_ch_calc:   CALL  motor_on          ; arrancar motor
  503.                MOV   DX,3F7h
  504.                IN    AL,DX             ; leer línea de cambio de disco
  505.                SHL   AL,1
  506.                JC    det_ch_yes        ; hay cambio de disco
  507.                XOR   AH,AH             ; no lo hay
  508. det_ch_end:    MOV   DS:[41h],AH       ; actualizar código de error
  509.                PUSH  AX
  510.                PUSH  SI
  511.                PUSH  DS
  512.                MOV   SI,0
  513.                MOV   DS,SI
  514.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  515.                MOV   AL,[SI+2]
  516.                POP   DS
  517.                MOV   DS:[40h],AL       ; tiempo detención motor
  518.                POP   SI
  519.                POP   AX
  520.                JMP   main_exit
  521. detect_change  ENDP
  522.  
  523. ; ------------ Funciones 2, 3 y 4: Leer, escribir y verificar.
  524.  
  525. read_wr_verify PROC
  526.                CMP   DL,1
  527.                JBE   rwv_posible
  528.                MOV   AH,1              ; función/parámetro incorrecto
  529. rwv_err:       MOV   DS:[41h],AH       ; código de error
  530.                XOR   AL,AL
  531.                STC
  532.                JMP   rwv_exit
  533. rwv_posible:   MOV   SI,90h
  534.                PUSH  DX
  535.                XOR   DH,DH
  536.                ADD   SI,DX               ; [SI] -> estado físico
  537.                CMP   BYTE PTR DS:[SI],0  ; ¿estado indeterminado?...
  538.                POP   DX
  539.                JNE   rwv_state_ok      ; no
  540.                PUSH  AX
  541.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  542.                JZ    rwv_type_ok       ; ha resultado posible
  543.                POP   AX
  544. rwv_not_ready: MOV   AH,80h            ; "unidad no preparada"
  545.                JMP   rwv_err
  546. rwv_type_ok:   OR    AL,AL             ; ¿existe la unidad?
  547.                POP   AX
  548.                JZ    rwv_not_ready     ; no existe esa unidad
  549.                MOV   BYTE PTR DS:[SI],2    ; probando 1.2M en 1.2M
  550. rwv_state_ok:  MOV   DI,3Fh
  551.                AND   BYTE PTR DS:[DI],7Fh  ; operación Read/Verify
  552.                CMP   AH,3                  ; ¿operación de escritura?
  553.                JNE   rwv_nowr
  554.                OR    BYTE PTR DS:[DI],80h  ; operación Write/Format
  555. rwv_nowr:      PUSH  SI
  556.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  557.                JNZ   rwv_media_ok
  558.                CMP   AL,1
  559.                JE    rwv_set360            ; es de 360K
  560.                CMP   AL,3
  561.                JNE   rwv_media_ok          ; no es de 720K
  562.                MOV   BYTE PTR DS:[SI],97h    ; forzar medio de 720K
  563.                JMP   rwv_media_ok
  564. rwv_set360:    MOV   BYTE PTR DS:[SI],93h    ; forzar medio de 360K
  565. rwv_media_ok:  CALL  motor_on          ; arrancar motores
  566.                CALL  read_disk_chg     ; leer línea de cambio de disco
  567.                POP   SI
  568.                JNC   rwv_no_dschg      ; no hay cambio de disco
  569. rwv_end_err:   CALL  end_io_access
  570.                JMP   rwv_err
  571. rwv_no_dschg:  TEST  BYTE PTR DS:[SI],10h  ; ¿densidad determinada?
  572.                JNZ   rwv_set_rate          ; en efecto
  573.                CALL  detect_media          ; pues determinarla
  574.                JC    rwv_end_err           ; problemas
  575.                JMP   rwv_dens_ok
  576. rwv_set_rate:  CALL  select_rate       ; seleccionar la velocidad
  577. rwv_dens_ok:   MOV   SI,90h
  578.                PUSH  DX
  579.                XOR   DH,DH
  580.                ADD   SI,DX             ; [SI] -> estado físico unidad
  581.                POP   DX
  582.                MOV   AX,0AF03H                ; AF byte 0 specify 2.88
  583.                CMP   BYTE PTR DS:[SI],0D7h    ; ¿2.88M?
  584.                JE    rwv_spec_ok              ; así es
  585.                MOV   AX,0DF03h                ; DF para 360/1.2/720
  586.                CMP   BYTE PTR DS:[SI],17h     ; ¿1.44M?
  587.                JNE   rwv_spec_ok              ; no
  588.                MOV   AH,0BFh                  ; sí
  589. rwv_spec_ok:   MOV   SI,AX                    ; SI 0-7: orden specify
  590.                MOV   DI,2                     ; DI 0-7: byte 1 specify
  591.                MOV   CH,3                     ; comando de 3 bytes
  592.                OR    BYTE PTR DS:[3Eh],80h    ; no esperar INT
  593.                CALL  exec_cmd
  594.                JC    rwv_end_err       ; fallo
  595.                MOV   AX,r_ax
  596.                XOR   AH,AH
  597.                PUSH  DS
  598.                XOR   SI,SI
  599.                MOV   DS,SI
  600.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  601.                MOV   CL,r_AL           ; [+]
  602.                ADD   CL,r_CL           ; [+] último sector a acceder
  603.                DEC   CL
  604.                CMP   CL,[SI+4]         ; [+] fix por si el DOS está
  605.                JBE   rwv_usok          ; [+] atontado
  606.                MOV   [SI+4],CL         ; [+]
  607. rwv_usok:      MOV   CL,[SI+3]         ; bytes/sector
  608.                SHL   AL,CL             ; multiplicar por nº sectores
  609.                MOV   CL,80h
  610.                MUL   CL                ; y por 128
  611.                POP   DS
  612.                DEC   AX                ; un byte menos...
  613.                MOV   CX,AX             ; ...cuenta para el DMA
  614.                CALL  eval_dir_DMA
  615.                JNC   rwv_dma_ok        ; no hay problemas con el DMA
  616.                MOV   CX,r_cx           ; restaurar CX
  617.                JMP   rwv_end_err       ; problemas con el DMA
  618. rwv_dma_ok:    MOV   AX,r_ax
  619.                CMP   AH,2              ; ¿operación de lectura?
  620.                JNE   rwv_no_read
  621.                MOV   AH,46h            ; byte de modo DMA para lectura
  622.                JMP   rwv_dma_set
  623. rwv_no_read:   CMP   AH,3              ; ¿escritura?
  624.                MOV   AH,4Ah            ; modo DMA para escritura
  625.                JZ    rwv_dma_set
  626.                MOV   AH,42h            ; modo DMA para verificación
  627. rwv_dma_set:   CALL  set_dma           ; preparar DMA
  628.                MOV   AX,r_ax
  629.                MOV   CX,r_cx           ; restaurar parámetros
  630.                JMP   perform_io        ; efectuar E/S
  631. io_performed:  CALL  end_io_access
  632.                OR    AL,AL
  633.                JZ    rwv_end
  634.                SUB   BL,CL             ; próximo sector-sector inicial
  635.                MOV   AL,BL             ; nº sectores transferidos
  636. rwv_end:       MOV   AH,DS:[41h]
  637.                OR    AH,AH             ; ¿error?
  638.                JZ    rwv_exit
  639.                STC                     ; señalizar error
  640. rwv_exit:      MOV   r_al,AL           ; nº sectores transferidos
  641.                JMP   main_exit
  642. read_wr_verify ENDP
  643.  
  644. ; ------------ Función 5: Formatear pista.
  645.  
  646. format_track   PROC
  647.                CMP   DL,1
  648.                JBE   fmt_do
  649.                MOV   AH,1              ; función/parámetro incorrecto
  650. fmt_exit_err:  MOV   DS:[41h],AH       ; código de error
  651.                STC
  652.                JMP   main_exit
  653. fmt_do:        MOV   SI,90h
  654.                PUSH  DX
  655.                XOR   DH,DH
  656.                ADD   SI,DX             ; [SI] -> estado físico unidad
  657.                POP   DX
  658.                CMP   BYTE PTR DS:[SI],0
  659.                MOV   AH,80h            ; "unidad no preparada"
  660.                JE    fmt_exit_err      ; indeterminado
  661.                MOV   DI,3Fh
  662.                OR    BYTE PTR DS:[DI],80h  ; no esperar INT
  663.                CALL  motor_on          ; arrancar motores
  664.                CALL  read_disk_chg     ; leer línea de cambio de disco
  665.                JNC   fmt_posible       ; no hay cambio de disco
  666. fmt_err:       CALL  end_io_access
  667.                JMP   fmt_exit_err      ; error
  668. fmt_posible:   CALL  select_rate       ; seleccionar la velocidad
  669.                CALL  send_specify      ; enviar comando specify
  670.                PUSH  DS
  671.                XOR   SI,SI
  672.                MOV   DS,SI
  673.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  674.               IFDEF  XTDEBUG           ; (se usó en las pruebas)
  675.                MOV   AL,r_AL           ; [+] sectores por pista
  676.                MOV   [SI+4],AL         ; [+]
  677.               ELSE
  678.                MOV   AL,[SI+4]         ; sectores por pista
  679.               ENDIF
  680.                POP   DS
  681.                XOR   AH,AH
  682.                MOV   CL,4
  683.                MUL   CL                ; 4 bytes para cada uno
  684.                MOV   CX,AX
  685.                DEC   CX                ; un byte menos...
  686.                CALL  eval_dir_DMA      ; ...cuenta para el DMA
  687.                JC    fmt_err           ; cruza frontera de DMA
  688.                MOV   AH,4Ah            ; modo DMA para escritura
  689.                CALL  set_dma           ; preparar DMA
  690.                MOV   CX,r_cx           ; restaurar CX
  691.                CALL  seek              ; llevar el cabezal a la pista
  692.                JNC   fmt_continue      ; no hay problemas
  693. fmt_err_res:   MOV   BX,42h
  694.                MOV   CX,7
  695.                PUSH  AX
  696.                CALL  get_results       ; leer bytes de resultados
  697.                POP   AX
  698.                JMP   fmt_exit          ; error
  699. fmt_continue:  XSHL  DH,2
  700.                OR    DH,DL             ; DH = byte 1 del comando
  701.                MOV   DL,0CDh           ; comando de formateo del FDC
  702.                PUSH  DS
  703.                XOR   SI,SI
  704.                MOV   DS,SI
  705.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  706.                PUSH  AX
  707.                MOV   AX,[SI+7]         ; GAP formateo/byte de relleno
  708.                MOV   [BP],AX           ; preservarlo
  709.                POP   AX
  710.                MOV   DI,[SI+3]         ; bytes/sector, sectores/pista
  711.                POP   DS
  712.                MOV   SI,DX             ; primeros bytes del comando
  713.                MOV   CH,6              ; comando de 6 bytes
  714.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  715.                CALL  exec_cmd
  716.                JC    fmt_err_res       ; hay error
  717.                MOV   BX,42h
  718.                MOV   CX,7
  719.                CALL  get_results       ; leer bytes de resultados
  720.                JC    fmt_exit
  721.                CALL  get_bios_err      ; obtener código de error
  722. fmt_exit:      MOV   DS:[41h],AH       ; código de error
  723.                CALL  end_io_access
  724.                MOV   AH,DS:[41h]
  725.                OR    AH,AH
  726.                JZ    fmt_end           ; no hay error
  727.                STC
  728. fmt_end:       JMP   main_exit
  729. format_track   ENDP
  730.  
  731. ; ------------ Función 8: Obtener parámetros de disco.
  732.  
  733. get_drv_param  PROC
  734.                CMP   DL,80h
  735.                JB    gdrv_do
  736.                MOV   AH,1              ; función/parámetro incorrecto
  737.                MOV   DS:[41h],AH       ; código de error
  738.                STC
  739.                JMP   main_exit
  740. gdrv_do:       XOR   DI,DI
  741.                XOR   SI,SI
  742.                XOR   DH,DH
  743.                MOV   AL,DS:[10h]       ; hardware instalado
  744.                AND   AL,0C1h           ; nº disqueteras (7-6) y bit
  745.                MOV   DI,2              ; que indica arrancable (0)
  746.                CMP   AL,41h            ; ¿dos disqueteras? (DI=2)
  747.                JE    gdrv_ndisk_ok     ; en efecto
  748.                DEC   DI
  749.                CMP   AL,1              ; ¿una disquetera? (DI=1)
  750.                JE    gdrv_ndisk_ok     ; así es
  751.                JMP   gdrv_res_null     ; no hay disqueteras
  752. gdrv_ndisk_ok: CMP   DL,1
  753.                JBE   gdrv_a_or_b       ; la disquetera es A: o B:
  754.                JMP   gdrv_half_res
  755. gdrv_a_or_b:   CALL  peek_cmos         ; leer tipo de disqueteras
  756.                OR    DL,DL
  757.                JNZ   gdrv_sel
  758.                MOV   CL,4
  759.                SHR   AL,CL             ; dejar disquetera en bits 0-3
  760. gdrv_sel:      AND   AL,0Fh
  761.                JZ    gdrv_media?       ; no existe esa unidad
  762.                CMP   AL,5
  763.                JA    gdrv_media?       ; es mayor de 2.88M
  764.                XOR   AH,AH
  765.                MOV   SI,AX
  766.                MOV   DH,AL
  767.                MOV   BX,90h
  768.                ADD   BL,DL             ; [BX] -> estado físico unidad
  769.                MOV   AL,[BX]
  770.                TEST  AL,10h            ; ¿densidad determinada?
  771.                JNZ   gdrv_calc_p       ; en efecto
  772.                CMP   SI,1              ; ¿unidad de 360K?
  773.                MOV   AL,93h            ; 360K en 360K, 250 Kbps
  774.                JE    gdrv_media_ok
  775.                CMP   SI,2              ; ¿unidad de 1.2M?
  776.                MOV   AL,2              ; "intentando 1.2M"
  777.                JE    gdrv_media_ok
  778.                CMP   SI,3              ; ¿unidad de 720K?
  779.                MOV   AL,97h            ; 720K en 720K, 250 Kbps
  780.                JE    gdrv_media_ok
  781.                CMP   SI,4              ; ¿unidad de 1.44M?
  782.                MOV   AL,7              ; "intentando 1.44M"
  783.                JE    gdrv_media_ok
  784.                MOV   AL,0C7h           ; 2.88M en 2.88M
  785. gdrv_media_ok: MOV   [BX],AL
  786.                JMP   gdrv_calc_p       ; medio físico asignado
  787. gdrv_media?:   MOV   BX,90h
  788.                ADD   BL,DL             ; [BX] -> estado físico unidad
  789.                MOV   AL,[BX]
  790.                TEST  AL,10h            ; ¿densidad determinada?
  791.                JZ    gdrv_eval         ; no
  792.                MOV   AH,AL
  793.                AND   AL,0C0h           ; aislar bits de velocidad
  794.                CMP   AL,80h            ; ¿250 Kbps?
  795.                MOV   SI,2              ; 1.2M
  796.                JNE   gdrv_m144?
  797.                TEST  AH,4
  798.                MOV   SI,1              ; 360K
  799.                JZ    gdrv_calc_p
  800.                MOV   SI,4              ; 1.44M
  801. gdrv_m144?:    TEST  AH,7
  802.                JZ    gdrv_calc_p
  803.                MOV   SI,4              ; 1.44M
  804. gdrv_calc_p:   MOV   BX,DI
  805.                MOV   DI,SI
  806.                DEC   DI
  807.                ADD   DI,DI
  808.                MOV   AX,CS:tab_disksize[DI] ; AL sect/pista, AH pistas
  809.                MOV   r_dh,1                 ; dos cabezales
  810.                MOV   DI,CS:tab_ptr_1e[DI]   ; DI -> tabla parámetros
  811.                PUSH  CS
  812.                POP   ES                ; ES:DI -> parámetros disco
  813. gdrv_set_res:  MOV   r_dl,BL           ; número de unidades
  814.                MOV   r_ch,AH           ; mayor número de cilindro
  815.                MOV   r_cl,AL           ; mayor número de sector
  816.                MOV   r_bl,DH           ; tipo de la unidad
  817.                MOV   r_bh,0
  818.                MOV   r_es,ES           ; ES:DI para la salida
  819.                MOV   r_di,DI
  820.                XOR   AX,AX
  821.                MOV   DS:[41h],AH       ; resultado correcto
  822.                MOV   r_al,AL
  823.                JMP   main_exit
  824. gdrv_res_null: XOR   DI,DI             ; devolver todo a 0
  825. gdrv_half_res: XOR   DH,DH
  826.                XOR   AX,AX
  827.                MOV   ES,AX
  828.                MOV   r_dh,0
  829.                MOV   BX,DI
  830.                XOR   DI,DI
  831.                JMP   gdrv_set_res      ; resultado trivial
  832. gdrv_eval:     MOV   BX,DI
  833.                OR    SI,SI
  834.                JZ    gdrv_res_null     ; no existe la unidad
  835.                CMP   SI,3
  836.                JBE   gdrv_calc_p       ; es de 5¼
  837.                XOR   SI,SI
  838.                JMP   gdrv_res_null
  839. get_drv_param  ENDP
  840.  
  841. ; ------------ Función 18h: Establecer densidad de formateo.
  842.  
  843. set_media_fmt  PROC
  844.                CMP   DL,1
  845.                JBE   setm_do
  846.                MOV   AH,1              ; función/parámetro incorrecto
  847. setm_exit_err: STC
  848.                JMP   main_exit
  849. setm_do:       CALL  get_drive_type    ; obtener tipo disquetera en AL
  850.                JZ    setm_drv_ok
  851. setm_drv_unkn: MOV   AH,0Ch            ; tipo de unidad desconocido
  852.                JMP   setm_exit_err
  853. setm_drv_ok:   XOR   AH,AH
  854.                MOV   DI,AX             ; tipo de unidad
  855.                MOV   DL,r_dl
  856.                MOV   BX,90h
  857.                XOR   DH,DH
  858.                ADD   BX,DX             ; [BX] -> estado físico unidad
  859.                CMP   AL,1              ; ¿360K?
  860.                JNE   setm_not360
  861.                MOV   CX,r_cx           ; restaurar CX
  862.                CMP   CX,2709h          ; ¿40 pistas 9 sectores?
  863.                LEA   SI,t360in360
  864.                JNZ   setm_drv_unkn     ; sólo se permite ese formato
  865.                JMP   setm_360in360
  866. setm_not360:   CMP   AL,3              ; ¿720K?
  867.                JNE   setm_not720
  868.                MOV   CX,r_cx           ; restaurar CX
  869.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  870.                JNE   setm_drv_unkn     ; sólo se permite ese formato
  871.                JMP   setm_setm
  872. setm_not720:   CMP   AL,4              ; ¿1.44M?
  873.                JE    setm_1440
  874.                CMP   AL,2              ; ¿1.2M?
  875.                JE    setm_1200
  876.                CMP   AL,5              ; ¿2.88M?
  877.                JNE   setm_drv_unkn
  878.                MOV   CX,r_cx           ; 2.88M: restaurar CX
  879.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  880.                JE    setm_setm         ; correcto
  881.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  882.                JE    setm_setm         ; correcto
  883.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  884.                JE    setm_setm         ; correcto
  885.                JMP   setm_drv_unkn     ; permitir sólo esos formatos
  886. setm_1200:     MOV   CX,r_cx           ; restaurar CX
  887.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  888.                JE    setm_setm         ; correcto
  889.                CMP   CX,2709h          ; ¿80 pistas 9 sectores?
  890.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  891.                JMP   setm_setm         ; correcto
  892. setm_1440:     MOV   CX,r_cx           ; restaurar CX
  893.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  894.                JE    setm_setm         ; correcto
  895.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  896.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  897. setm_setm:     MOV   CX,r_cx           ; restaurar CX
  898.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  899.                MOV   AL,17h            ; su byte de medio físico
  900.                LEA   SI,t1440          ; es 1.44M
  901.                MOV   DH,0              ; 500 Kbps
  902.                JZ    setm_m_ok
  903.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  904.                MOV   AL,97h            ; su byte de medio físico
  905.                LEA   SI,t720           ; es 720K
  906.                MOV   DH,2              ; 250 Kbps
  907.                JZ    setm_m_ok
  908.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  909.                MOV   AL,15h            ; su byte de medio físico
  910.                LEA   SI,t1200          ; es 1.2M
  911.                MOV   DH,0              ; 500 Kbps
  912.                JZ    setm_m_ok
  913.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  914.                MOV   AL,0D7h           ; su byte de medio físico
  915.                LEA   SI,t2880          ; es 2.88M
  916.                MOV   DH,3              ; 1 Mbps
  917.                JZ    setm_m_ok
  918.                MOV   AL,74h            ; byte medio físico 360K en 1.2
  919.                LEA   SI,t360en1200     ; es 360K en 1.2M
  920.                MOV   DH,1              ; 300 Kbps
  921. setm_m_ok:     MOV   [BX],AL           ; establecer medio físico
  922.                PUSH  DX
  923.                CALL  set_rate          ; velocidad de transferencia DH
  924.                POP   DX
  925.                MOV   AL,[BX]
  926.                AND   AL,0C0h
  927.                AND   BYTE PTR DS:[8Bh],3Fh  ; borrar bits de velocidad
  928.                OR    BYTE PTR DS:[8Bh],AL   ; nueva velocidad
  929.                MOV   r_di,SI
  930.                MOV   r_es,CS              ; retornar tabla parámetros
  931.                MOV   BYTE PTR DS:[41h],0  ; no hay error
  932.                XOR   AH,AH
  933.                JMP   main_exit
  934. setm_360in360: MOV   DH,2                 ; 250 Kbps
  935.                MOV   AL,93h               ; 360K en 360K
  936.                JMP   setm_m_ok
  937. set_media_fmt  ENDP
  938.  
  939. ; ------------ Recalibrar.
  940.  
  941. recalibrate    PROC
  942.                PUSH  SI
  943.                PUSH  CX
  944.                PUSH  DX
  945.                MOV   DH,DL
  946.                MOV   DL,7              ; comando "recalibrate"
  947.                MOV   SI,DX
  948.                MOV   CH,2              ; comando de 2 bytes
  949.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  950.                CALL  exec_cmd
  951.                JC    recal_end         ; fallo
  952.                MOV   SI,8              ; "leer estado interrupciones"
  953.                MOV   CH,1              ; comando de 1 byte
  954.                OR    BYTE PTR DS:[3Eh],80h  ; sin espera de IRQ
  955.                CALL  exec_cmd
  956.                JC    recal_end         ; fallo
  957.                MOV   BX,42h
  958.                MOV   CX,2              ; 2 bytes de resultado
  959.                CALL  get_results       ; almacenar resultado
  960.                JC    recal_end         ; fallo
  961.                MOV   BX,42h
  962.                MOV   AH,40h
  963.                MOV   DL,[BX]           ; ST0
  964.                AND   DL,60h
  965.                CMP   DL,60h            ; ¿terminación anormal y
  966.                STC                     ; seek-end?
  967.                JE    recal_end         ; fallo
  968.                POP   DX
  969.                PUSH  DX
  970.                XOR   DH,DH             
  971.                MOV   BX,94H
  972.                ADD   BX,DX
  973.                MOV   BYTE PTR DS:[BX],0  ; cilindro en curso = 0
  974.                MOV   CL,DL
  975.                MOV   DL,1
  976.                SHL   DL,CL
  977.                OR    DS:[3Eh],DL       ; unidad recalibrada
  978.               IFNDEF XT
  979.                MOV   CX,43h
  980.                CALL  wait_time         ; retardo de 1 ms
  981.               ELSE
  982.                MOV   CX,1
  983.                CALL  retardo           ; retardo de 1 ms
  984.               ENDIF
  985.                XOR   AH,AH
  986. recal_end:     MOV   DS:[41h],AH       ; código de error / acierto
  987.                POP   DX
  988.                POP   CX
  989.                POP   SI
  990.                RET
  991. recalibrate    ENDP
  992.  
  993. ; ------------ Llevar el cabezal al cilindro adecuado.
  994.  
  995. seek           PROC
  996.                PUSH  BX
  997.                PUSH  CX
  998.                MOV   AH,DS:[3Eh]       ; estado de recalibración
  999.                MOV   CL,DL
  1000.                INC   CL
  1001.                SHR   AH,CL
  1002.                JC    seek_only
  1003.                CALL  recalibrate       ; hay que recalibrar
  1004.                JNC   seek_only
  1005.                CALL  recalibrate       ; segundo intento
  1006.                JNC   seek_only
  1007.                JMP   seek_exit
  1008. seek_only:     MOV   BX,94H
  1009.                XOR   DH,DH
  1010.                ADD   BX,DX             ; [BX] -> cilindro actual
  1011.                MOV   SI,90h
  1012.                ADD   SI,DX             ; [SI] -> estado físico unidad
  1013.                MOV   DL,CH
  1014.                TEST  BYTE PTR DS:[SI],20h  ; ¿hacer double stepping?
  1015.                JZ    seek_cil_ok1
  1016.                ADD   DL,DL             ; sí: cilindro=cilindro*2
  1017. seek_cil_ok1:  CMP   [BX],DL           ; ¿ya estamos en ese cilindro?
  1018.                MOV   DX,r_dx
  1019.                JNE   seek_do           ; aún no
  1020.                CMP   BYTE PTR DS:[41h],40h  ; ¿hubo "seek error"?
  1021.                JE    seek_do
  1022.                XOR   AH,AH             ; no, seek innecesario
  1023.                JMP   seek_exit
  1024. seek_do:       XSHL  DH,2
  1025.                OR    DH,DL             ; byte 1 del comando seek
  1026.                MOV   DL,0FH            ; orden seek
  1027.                MOV   SI,DX
  1028.                MOV   CL,CH             ; cilindro
  1029.                MOV   DX,r_dx           ; unidad / cabezal
  1030.                MOV   BX,90h
  1031.                XOR   DH,DH
  1032.                ADD   BX,DX                 ; [BX] -> estado físico
  1033.                TEST  BYTE PTR DS:[BX],20h  ; ¿hacer double stepping?
  1034.                JZ    seek_cil_ok2      ; no
  1035.                ADD   CL,CL             ; sí: cilindro=cilindro*2
  1036. seek_cil_ok2:  MOV   DI,CX
  1037.                MOV   CH,3              ; comando de 3 bytes
  1038.                AND   BYTE PTR DS:[3Eh],7Fh  ; hay que esperar IRQ
  1039.                CALL  exec_cmd
  1040.                JNC   seek_ok           ; seek correcto
  1041.                JMP   seek_result
  1042. seek_ok:       MOV   SI,8              ; "leer estado interrupciones"
  1043.                MOV   CH,1              ; comando de 1 byte
  1044.                OR    BYTE PTR DS:[3Eh],80h  ; no hay que esperar IRQ
  1045.                CALL  exec_cmd
  1046.                JC    seek_result       ; fallo
  1047.                MOV   BX,42h
  1048.                MOV   CX,2
  1049.                CALL  get_results       ; leer bytes de resultados
  1050.                JC    seek_result
  1051.                MOV   BX,42h
  1052.                MOV   AH,40h            ; "seek error"
  1053.                MOV   DL,[BX]           ; ST0
  1054.                AND   DL,60h
  1055.                CMP   DL,60h            ; comprobarlo
  1056.                STC
  1057.                JE    seek_result       ; terminación brusca
  1058.                MOV   DX,r_dx           ; restaurar DX
  1059.                POP   CX
  1060.                PUSH  CX                ; restaurar CX
  1061.                MOV   SI,94H
  1062.                XOR   DH,DH
  1063.                ADD   SI,DX
  1064.                MOV   [SI],CH           ; actualizar cilindro actual
  1065.                MOV   BX,90h
  1066.                ADD   BX,DX             ; [BX] -> estado físico unidad
  1067.                MOV   BL,[BX]
  1068.                TEST  BL,20h            ; ¿double stepping?
  1069.                JZ    seek_cil_ok3
  1070.                ADD   [SI],CH           ; pues cilindro*2
  1071. seek_cil_ok3:  PUSH  DS
  1072.                XOR   SI,SI
  1073.                MOV   DS,SI
  1074.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1075.                MOV   AL,[SI+9]         ; tiempo estabilización cabezal
  1076.                POP   DS
  1077.                TEST  BYTE PTR DS:[3Fh],80h  ; ¿operación en curso?
  1078.                JZ    seek_wait         ; es lectura o verificación
  1079.                OR    AL,AL
  1080.                JNZ   seek_wait         ; escritura, cte != 0
  1081.                CMP   BL,17h
  1082.                MOV   AL,0Fh
  1083.                JE    seek_wait         ; 15 ms excepto para 360K
  1084.                AND   BL,7
  1085.                MOV   AL,14h
  1086.                JZ    seek_wait         ; 20 ms para unidades de 360K
  1087.                CMP   BL,3
  1088.                JE    seek_wait         ; 20 ms para unidades de 360K
  1089.                MOV   AL,0Fh            ; 15 ms para demás unidades
  1090. seek_wait:     OR    AL,AL
  1091.                JZ    seek_wait_end
  1092.               IFNDEF XT
  1093.                MOV   CX,43h
  1094.                CALL  wait_time         ; esperar 1 ms...
  1095.               ELSE
  1096.                MOV   CX,1
  1097.                CALL  retardo           ; retardo de 1 ms
  1098.               ENDIF
  1099.                DEC   AL
  1100.                JMP   seek_wait         ; ...durante AL veces
  1101. seek_wait_end: XOR   AH,AH
  1102. seek_result:   MOV   DS:[41h],AH       ; resultado
  1103. seek_exit:     MOV   DX,r_dx           ; restaurar DX
  1104.                POP   CX
  1105.                POP   BX
  1106.                RET
  1107. seek           ENDP
  1108.  
  1109. ; ------------ Ejecutar operación de E/S a través del FDC.
  1110.  
  1111. perform_io     PROC
  1112.                CALL  seek
  1113.                JNC   p_io
  1114. p_io_dsk_err:  MOV   AL,0              ; fallo
  1115.                PUSH  AX
  1116.                MOV   BX,42h
  1117.                MOV   CX,7
  1118.                CALL  get_results       ; leer bytes de resultados
  1119.                POP   AX
  1120.                JMP   p_io_exit
  1121. p_io:          PUSH  DS                ; preparar bytes comando R/W
  1122.                XOR   SI,SI
  1123.                MOV   DS,SI
  1124.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1125.                MOV   AX,[SI+2]
  1126.                AND   AX,0FF00h         ; AH = bytes por sector
  1127.                MOV   AL,CL             ; AL = primer sector
  1128.                MOV   [BP],AX
  1129.                MOV   BX,[SI+4]         ; BL=sectores/pista, BH=GAP R/W
  1130.                MOV   CL,[SI+6]         ; CL=longitud de sector (tam=0)
  1131.                POP   DS
  1132.                MOV   SI,90h
  1133.                XOR   DH,DH
  1134.                ADD   SI,DX             ; nº sector/tamaño (bytes 4-5)
  1135.                MOV   DL,[SI]           ; estado físico de la unidad
  1136.                AND   DL,7
  1137.                MOV   DH,1Bh            ; GAP R/W para 1.2M/1.44M/2.88M
  1138.                CMP   DL,5
  1139.                JE    p_io_gap_ok       ; 1.2M en 1.2M
  1140.                CMP   BYTE PTR DS:[SI],17h
  1141.                JE    p_io_gap_ok            ; 1.44M
  1142.                CMP   BYTE PTR DS:[SI],0D7h
  1143.                JE    p_io_gap_ok            ; 2.88M
  1144.                MOV   DH,23h            ; GAP R/W para 360K en 1.2M
  1145.                CMP   DL,4
  1146.                JE    p_io_gap_ok       ; 360K en 1.2M
  1147.                MOV   DH,2Ah            ; GAP R/W para demás casos
  1148. p_io_gap_ok:   MOV   BH,DH             ; BX=numsect/GAP (bytes 6-7)
  1149.                MOV   DX,r_dx           ; restaurar DX
  1150.                PUSH  CX
  1151.                MOV   CL,CH             ; cilindro
  1152.                MOV   CH,DH             ; cabezal
  1153.                MOV   DI,CX             ; cabezal/cilindro (bytes 2-3)
  1154.                XSHL  DH,2
  1155.                OR    DH,DL             ; byte 1 de comando FDC
  1156.                MOV   DL,0E6h           ; comando leer datos
  1157.                MOV   AX,r_ax           ; orden
  1158.                CMP   AH,3              ; ¿write?
  1159.                JNE   p_io_orden_ok
  1160.                MOV   DL,0C5h           ; comando escribir datos
  1161. p_io_orden_ok: MOV   SI,DX             ; (bytes 0-1 de la orden)
  1162.                POP   CX
  1163.                MOV   CH,9
  1164.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1165.                CALL  exec_cmd
  1166.                JNC   p_io_dsk_ok
  1167.                JMP   p_io_dsk_err      ; fallo
  1168. p_io_dsk_ok:   MOV   BX,42h
  1169.                MOV   CX,7
  1170.                CALL  get_results       ; leer bytes de resultados
  1171.                JNC   p_io_res_ok
  1172.                MOV   AL,0
  1173.                JMP   p_io_exit         ; fallo: respetar código error
  1174. p_io_res_ok:   CALL  get_bios_err
  1175. p_io_exit:     MOV   DS:[41h],AH
  1176.                MOV   DX,r_dx           ; restaurar registros
  1177.                MOV   BX,r_bx
  1178.                MOV   CX,r_cx
  1179.                JMP   io_performed      ; continuar operación E/S
  1180. perform_io     ENDP
  1181.  
  1182. ; ------------ Arrancar motor si no lo está.
  1183.  
  1184. motor_on       PROC
  1185.                PUSH  DX
  1186.                PUSH  CX
  1187.                CLI                     ; * evitar reentrada
  1188.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1189.                AND   BYTE PTR DS:[3Fh],0CFh  ; a 0 bits de disquetera
  1190.                MOV   CH,DL
  1191.                XSHL  DL,4
  1192.                OR    DS:[3Fh],DL       ; nueva disquetera seleccionada
  1193.                MOV   CL,CH
  1194.                MOV   DL,DS:[3Fh]       ; estado de motores
  1195.                INC   CL
  1196.                SHR   DL,CL
  1197.                JC    motor_is_on       ; motor ya en marcha
  1198.                MOV   DL,1
  1199.                DEC   CL
  1200.                SHL   DL,CL
  1201.                OR    DS:[3Fh],DL       ; señalizar que está en marcha
  1202.                STI                     ; * fin de la fase crítica
  1203.                MOV   AL,DS:[3Fh]       ; estado de motores
  1204.                XROR  AL,4
  1205.                OR    AL,0CH            ; no resetear, modo DMA
  1206.                MOV   DX,3F2h
  1207.                OUT   DX,AL             ; registro salida digital
  1208.                MOV   AX,90FDh
  1209.                INT   15h               ; permitir multitarea
  1210.                JC    motor_on_end
  1211.                MOV   AH,DS:[3Fh]
  1212.                PUSH  DS
  1213.                PUSH  SI
  1214.                XOR   SI,SI
  1215.                MOV   DS,SI
  1216.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1217.                MOV   AL,[SI+0Ah]
  1218.                POP   SI                ; AL = tiempo aceleración motor
  1219.                POP   DS                ;      en octavos de segundo
  1220.                SHL   AH,1
  1221.                JNC   motor_on_rv       ; operación read/verify
  1222.                CMP   AL,8
  1223.                JAE   motor_on_wait
  1224.                MOV   AL,8
  1225.                JMP   motor_on_wait     ; escritura: al menos 1 segundo
  1226. motor_on_rv:   CMP   AL,5
  1227.                JAE   motor_on_wait
  1228.                MOV   AL,5              ; read/verify: al menos 625 ms
  1229. motor_on_wait:IFNDEF XT
  1230.                MOV   CX,208EH
  1231.                CALL  wait_time         ; retardo de unos 125 ms
  1232.               ELSE
  1233.                MOV   CX,125
  1234.                CALL  retardo           ; retardo de unos 125 ms
  1235.               ENDIF
  1236.                DEC   AL
  1237.                JNZ   motor_on_wait     ; completar retardo
  1238.                JMP   motor_on_end
  1239. motor_is_on:   STI
  1240.                MOV   AL,DS:[3Fh]       ; estado de motores
  1241.                XROR  AL,4
  1242.                OR    AL,0CH            ; no resetear, modo DMA
  1243.                MOV   DX,3F2h
  1244.                OUT   DX,AL             ; seleccionar unidad
  1245. motor_on_end:  POP   CX
  1246.                POP   DX
  1247.                RET
  1248. motor_on       ENDP
  1249.  
  1250. ; ------------ Asignar cuenta para detención motor y devolver en BL
  1251. ;              y AL el próximo número de sector a transferir.
  1252.  
  1253. end_io_access  PROC
  1254.                PUSH  AX
  1255.                PUSH  DS
  1256.                XOR   BX,BX
  1257.                MOV   DS,BX
  1258.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1259.                MOV   AH,[BX+2]         ; tics hasta detención motor
  1260.                MOV   AL,[BX+4]
  1261.                INC   AL                ; sectores/pista + 1
  1262.                POP   DS
  1263.                MOV   BX,42h
  1264.                CMP   CH,[BX+3]         ; ¿mismo cilindro resultante?
  1265.                JNE   end_io_exit
  1266.                CMP   DH,[BX+4]         ; ¿mismo cabezal resultante?
  1267.                JNE   end_io_exit
  1268.                MOV   AL,[BX+5]         ; número de sector resultante
  1269. end_io_exit:   MOV   DS:[40h],AH       ; tiempo para detención motor
  1270.                MOV   BL,AL             ; último nº sector transferido
  1271.                POP   AX
  1272.                RET
  1273. end_io_access  ENDP
  1274.  
  1275. ; ------------ Leer la línea de cambio de disco y bajarla si está
  1276. ;              activa.
  1277.  
  1278. read_disk_chg  PROC
  1279.                PUSH  CX
  1280.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1281.                MOV   AH,0
  1282.                JNZ   fallo_cmos
  1283.                CMP   AL,3              ; [+] Evitar test en 720K:
  1284.                JE    rdchg_set_cod     ; [+] Bug en BIOS AMI original?
  1285.                DEC   AL
  1286.                JZ    rdchg_set_cod     ; evitar test en 360K
  1287. fallo_cmos:    MOV   AL,[SI]           ; estado físico de la unidad
  1288.                AND   AL,7
  1289.                JZ    rdchg_set_cod     ; evitar test en 360K
  1290.                CMP   AL,3
  1291.                JE    rdchg_set_cod     ; evitar test en 360K
  1292.                MOV   DX,3F7h           ; registro de entrada digital
  1293.                IN    AL,DX             ; leer línea de cambio de disco
  1294.                SHL   AL,1
  1295.                JNC   rdchg_exit        ; no hay cambio de disco
  1296.                AND   BYTE PTR DS:[SI],0EFH  ; medio no determinado
  1297.                CALL  full_init         ; inicialización plena
  1298.                JC    rdchg_exit        ; fallo
  1299.                MOV   DX,r_dx           ; restaurar DX
  1300.                MOV   CH,1
  1301.                CALL  seek              ; cabezal a cilindro 1
  1302.                JC    rdchg_exit
  1303.                MOV   CH,0
  1304.                CALL  seek              ; cabezal a cilindro 0
  1305.                JC    rdchg_exit
  1306.                MOV   AH,6              ; error "disk changed"
  1307.                MOV   DX,3F7h
  1308.                IN    AL,DX             ; leer línea de cambio de disco
  1309.                SHL   AL,1
  1310.                JNC   rdchg_set_cod     ; se ha podido bajar
  1311.                MOV   AH,80h            ; no se pudo: no hay disquete
  1312. rdchg_set_cod: OR    AH,AH
  1313.                JZ    rdchg_exit
  1314.                STC
  1315. rdchg_exit:    MOV   DX,r_dx           ; restaurar DX
  1316.                POP   CX
  1317.                RET
  1318. read_disk_chg  ENDP
  1319.  
  1320. ; ------------ Programar el DMA para efectuar la E/S.
  1321.  
  1322. set_dma        PROC
  1323.                PUSH  AX
  1324.                PUSH  DX
  1325.                CLI
  1326.                MOV   AL,AH
  1327.                OUT   0CH,AL            ; clear first/last flip-flop
  1328.                JMP   SHORT $+2         ; retardo para E/S
  1329.                JMP   SHORT $+2
  1330.                OUT   0BH,AL            ; registro de modo del DMA
  1331.                JMP   SHORT $+2
  1332.                JMP   SHORT $+2
  1333.                MOV   AL,CL
  1334.                OUT   5,AL
  1335.                JMP   SHORT $+2
  1336.                JMP   SHORT $+2
  1337.                MOV   AL,CH
  1338.                OUT   5,AL              ; enviada cuenta de bytes
  1339.                JMP   SHORT $+2
  1340.                JMP   SHORT $+2
  1341.                MOV   AL,BL
  1342.                OUT   4,AL
  1343.                JMP   SHORT $+2
  1344.                JMP   SHORT $+2
  1345.                MOV   AL,BH
  1346.                OUT   4,AL              ; enviada dirección base
  1347.                JMP   SHORT $+2
  1348.                JMP   SHORT $+2
  1349.                MOV   AX,ES
  1350.                OUT   81H,AL            ; registro de página canal 2
  1351.                JMP   SHORT $+2
  1352.                JMP   SHORT $+2
  1353.                MOV   AL,2
  1354.                OUT   0AH,AL            ; habilitar canal 2 del DMA
  1355.                STI
  1356.                POP   DX
  1357.                POP   AX
  1358.                RET
  1359. set_dma        ENDP
  1360.  
  1361. ; ------------ Calcular parámetros para programar el DMA.
  1362.  
  1363. eval_dir_DMA   PROC
  1364.                PUSH  CX
  1365.                XOR   AX,AX
  1366.                MOV   CX,ES             ; segmento ES
  1367.                SHL   CX,1              ; desplazar...
  1368.                RCL   AL,1
  1369.                SHL   CX,1
  1370.                RCL   AL,1
  1371.                SHL   CX,1
  1372.                RCL   AL,1
  1373.                SHL   CX,1
  1374.                RCL   AL,1              ; ... AL:CX >> 4
  1375.                MOV   BX,r_bx           ; offset BX
  1376.                ADD   BX,CX
  1377.                ADC   AX,0              ; AX:BX dirección física 20 bit
  1378.                MOV   ES,AX             ; página de DMA
  1379.                POP   CX
  1380.                MOV   AX,CX
  1381.                ADD   AX,BX
  1382.                JNC   eval_dma_ret      ; no cruza frontera de 64k
  1383.                MOV   AH,9              ; "DMA across 64k boundary"
  1384. eval_dma_ret:  RET
  1385. eval_dir_DMA   ENDP
  1386.  
  1387. ; ------------ Enviar comando completo al FDC de CH bytes, contenido
  1388. ;              en SI, DI, [BP], BX y CL (parte baja - alta).
  1389.  
  1390. send_full_cmd  PROC
  1391.                MOV   AX,SI
  1392.                MOV   AH,AL
  1393.                CALL  fdc_write         ; enviar SI-L
  1394.                DEC   CH
  1395.                JBE   send_full_ret     ; acabado (ZF=1) ó error (CF=1)
  1396.                MOV   AX,SI
  1397.                CALL  fdc_write         ; enviar SI-H
  1398.                DEC   CH
  1399.                JBE   send_full_ret
  1400.                MOV   AX,DI
  1401.                MOV   AH,AL
  1402.                CALL  fdc_write         ; enviar DI-L
  1403.                DEC   CH
  1404.                JBE   send_full_ret
  1405.                MOV   AX,DI
  1406.                CALL  fdc_write         ; enviar DI-H
  1407.                DEC   CH
  1408.                JBE   send_full_ret
  1409.                MOV   AX,[BP]
  1410.                MOV   AH,AL
  1411.                CALL  fdc_write         ; enviar [BP]-L
  1412.                DEC   CH
  1413.                JBE   send_full_ret
  1414.                MOV   AX,[BP]
  1415.                CALL  fdc_write         ; enviar [BP]-H
  1416.                DEC   CH
  1417.                JBE   send_full_ret
  1418.                MOV   AH,BL
  1419.                CALL  fdc_write         ; enviar BL
  1420.                DEC   CH
  1421.                JBE   send_full_ret
  1422.                MOV   AH,BH
  1423.                CALL  fdc_write         ; enviar BH
  1424.                DEC   CH
  1425.                JBE   send_full_ret
  1426.                MOV   AH,CL
  1427.                CALL  fdc_write         ; enviar CL
  1428. send_full_ret: RET
  1429. send_full_cmd  ENDP
  1430.  
  1431. ; ------------ Enviar comando al FDC con/sin espera de interrupción.
  1432.  
  1433. exec_cmd       PROC
  1434.                TEST  BYTE PTR DS:[3Eh],80h  ; ¿hay que esperar IRQ?
  1435.                JZ    exec_cmd_irq           ; sí
  1436.                AND   BYTE PTR DS:[3Eh],7Fh  ; no: devolver a 0 bit IRQ
  1437.                CALL  send_full_cmd          ; enviar comando
  1438.                RET
  1439. exec_cmd_irq:  CALL  send_full_cmd          ; enviar comando
  1440.                JC    exec_cmd_ret
  1441.                MOV   AX,9001h
  1442.                INT   15h                    ; permitir multitarea
  1443.                STI
  1444.                JC    exec_cmd_err
  1445.                CALL  wait_int               ; esperar IRQ
  1446.                JNC   exec_cmd_ok
  1447. exec_cmd_err:  MOV   AH,80h                 ; "not ready" (AH=80h)
  1448. exec_cmd_ret:  RET
  1449. exec_cmd_ok:   AND   BYTE PTR DS:[3Eh],7Fh  ; bit IRQ listo para otra
  1450.                XOR   AH,AH                  ; éxito
  1451.                RET
  1452. exec_cmd       ENDP
  1453.  
  1454. ; ------------ Enviar byte al FDC.
  1455.  
  1456.               IFNDEF XT
  1457.  
  1458. fdc_write      PROC
  1459.                PUSH  CX
  1460.                PUSH  DX
  1461.                MOV   CX,2
  1462.                CALL  wait_time         ; esperar 15-30 µs
  1463.                MOV   DX,3F4h           ; registro de estado
  1464.                PUSH  AX
  1465.                MOV   AH,40h
  1466.                XOR   CX,CX
  1467.                CALL  wait0             ; esperar FDC listo para OUT
  1468.                JC    fdc_wr_fail
  1469.                MOV   AH,80h
  1470.                XOR   CX,CX
  1471.                CALL  wait1
  1472.                JC    fdc_wr_fail       ; error
  1473.                POP   AX
  1474.                MOV   DX,3F5h           ; registro de datos
  1475.                MOV   AL,AH
  1476.                OUT   DX,AL             ; escribir el byte
  1477.                JMP   fdc_wr_ret
  1478. fdc_wr_fail:   POP   AX
  1479.                MOV   AH,80h            ; error "not ready"
  1480. fdc_wr_ret:    POP   DX
  1481.                POP   CX
  1482.                RET
  1483. fdc_write      ENDP
  1484.  
  1485.               ELSE
  1486.  
  1487. fdc_write      PROC
  1488.                XPUSH <CX, DX, AX>
  1489.                MOV   DX,3F4h           ; registro de estado del FDC
  1490.                XOR   CX,CX             ; evitar cuelgue total si falla
  1491. espera_wr:     IN    AL,DX             ; leer registro de estado
  1492.                TEST  AL,80h            ; ¿bit 7 inactivo?
  1493.                LOOPZ espera_wr         ; así es: el FDC está ocupado
  1494.                JCXZ  fdc_wr_nok
  1495.                POP   AX
  1496.                PUSH  AX
  1497.                INC   DX                ; apuntar al registro de datos
  1498.                MOV   AL,AH
  1499.                OUT   DX,AL             ; enviar byte al FDC
  1500.                XPOP  <AX, DX, CX>
  1501.                CLC
  1502.                RET
  1503. fdc_wr_nok:    POP   AX
  1504.                MOV   AH,80h            ; timeout
  1505.                XPOP  <DX, CX>
  1506.                STC
  1507.                RET
  1508. fdc_write      ENDP
  1509.  
  1510.               ENDIF
  1511.  
  1512. ; ------------ Leer del FDC CX bytes de resultado en [BX++].
  1513.  
  1514. get_results    PROC
  1515.                PUSH  DX
  1516. get_one_byte:  PUSH  CX
  1517.                CALL  fdc_read
  1518.                POP   CX
  1519.                JC    get_res_ret       ; no hay más bytes que leer
  1520.                MOV   [BX],AL
  1521.                INC   BX
  1522.                LOOP  get_one_byte      ; leer todos los bytes
  1523.               IFNDEF XT
  1524.                MOV   CX,4
  1525.                CALL  wait_time         ; esperar 45-60 µs
  1526.               ELSE
  1527.                CALL  retardo53         ; retardo de 53 ms
  1528.               ENDIF
  1529.                MOV   DX,3F4h
  1530.                IN    AL,DX             ; leer registro de estado
  1531.                TEST  AL,10h
  1532.                JZ    get_res_ok        ; el FDC no está ocupado
  1533.                MOV   AH,20h
  1534.                STC                     ; lo estaba: "bad NEC"
  1535.                JMP   get_res_ret
  1536. get_res_ok:    XOR   AH,AH             ; operación correcta
  1537. get_res_ret:   POP   DX
  1538.                RET
  1539. get_results    ENDP
  1540.  
  1541. ; ------------ Leer byte del FDC.
  1542.  
  1543.               IFNDEF XT
  1544.  
  1545. fdc_read       PROC
  1546.                PUSH  DX
  1547.                MOV   CX,3
  1548.                CALL  wait_time         ; esperar 30-45 µs
  1549.                MOV   DX,3F4h           ; registro de estado
  1550.                MOV   AH,80h
  1551.                XOR   CX,CX
  1552.                CALL  wait1             ; esperar FDC listo para E/S
  1553.                MOV   AH,80h
  1554.                JC    fdc_read_end      ; error "not ready" (AH=80h)
  1555.                IN    AL,DX
  1556.                TEST  AL,40h            ; ¿el FDC quiere dar un byte?
  1557.                JNZ   fdc_read_ok
  1558.                MOV   AH,20H            ; no: error "bad NEC" (AH=20h)
  1559.                STC
  1560.                JMP   fdc_read_end
  1561. fdc_read_ok:   JMP   SHORT $+2         ; retardo para E/S
  1562.                JMP   SHORT $+2
  1563.                MOV   DX,3F5h           ; registro de datos
  1564.                IN    AL,DX             ; leer el byte
  1565. fdc_read_end:  POP   DX
  1566.                RET
  1567. fdc_read       ENDP
  1568.  
  1569.               ELSE
  1570.  
  1571. fdc_read       PROC
  1572.                XPUSH <CX, DX>
  1573.                MOV   DX,3F4h           ; registro de estado del FDC
  1574.                XOR   CX,CX             ; evitar cuelgue total si falla
  1575. espera_rd:     IN    AL,DX             ; leer registro de estado
  1576.                TEST  AL,80h            ; ¿bit 7 inactivo?
  1577.                LOOPZ espera_rd         ; así es: el FDC está ocupado
  1578.                JCXZ  fdc_rd_nok
  1579.                INC   DX                ; apuntar al registro de datos
  1580.                IN    AL,DX             ; leer byte del FDC
  1581.                CLC
  1582.                XPOP  <DX, CX>
  1583.                RET
  1584. fdc_rd_nok:    MOV   AH,80h            ; timeout
  1585.                STC
  1586.                XPOP  <DX, CX>
  1587.                RET
  1588. fdc_read       ENDP
  1589.                
  1590.               ENDIF
  1591.  
  1592. ; ------------ Obtener código de error de la BIOS.
  1593.  
  1594. get_bios_err   PROC
  1595.                MOV   BX,42h            ; área de resultados del FDC
  1596.                MOV   BX,[BX]
  1597.                TEST  BL,0C0h           ; ¿que tal ST0?
  1598.                MOV   AH,0
  1599.                JZ    bios_err_det      ; ¡perfecto!
  1600.                TEST  BL,40h            ; ¿terminación brusca/anormal?
  1601.                MOV   AH,20H            ; "bad NEC"
  1602.                JZ    bios_err_det
  1603.                TEST  BH,1              ; ¿falta marca de direcciones?
  1604.                MOV   AH,2              ; "address mark not found"
  1605.                JNZ   bios_err_det
  1606.                TEST  BH,2              ; ¿protegido contra escritura?
  1607.                MOV   AH,3              ; "write-protect error"
  1608.                JNZ   bios_err_det
  1609.                TEST  BH,4              ; ¿sector no encontrado?
  1610.                MOV   AH,4              ; "sector not found"
  1611.                JNZ   bios_err_det
  1612.                TEST  BH,10H            ; ¿DMA no atendido a tiempo?
  1613.                MOV   AH,8              ; "DMA overrun"
  1614.                JNZ   bios_err_det
  1615.                TEST  BH,20H            ; ¿falla el CRC?
  1616.                MOV   AH,10H            ; "CRC error"
  1617.                JNZ   bios_err_det
  1618.                TEST  BH,80h            ; ¿acceso fuera de la pista?
  1619.                MOV   AH,4              ; "sector not found"
  1620.                JNZ   bios_err_det
  1621.                MOV   AH,20H            ; otro error: "bad NEC"
  1622. bios_err_det:  RET
  1623. get_bios_err   ENDP
  1624.  
  1625. ; ------------ Reinicializar la controladora de disquetes.
  1626.  
  1627. init_fdc       PROC
  1628.                CALL  reset_disk        ; resetear FDC
  1629.                JC    init_fin          ; fallo al resetear
  1630.                MOV   DX,3F4h           ; registro de estado del FDC
  1631.                IN    AL,DX
  1632.                TEST  AL,80h
  1633.                JZ    init_otravez      ; el FDC no está listo
  1634.                TEST  AL,40h
  1635.                JZ    init_bien         ; el FDC espera datos de la CPU
  1636. init_otravez:  CALL  reset_disk        ; otro intento más
  1637.                MOV   DX,3F4h
  1638.                IN    AL,DX
  1639.                TEST  AL,80h
  1640.                JZ    init_mal          ; nada, que no tira
  1641.                TEST  AL,40h
  1642.                JZ    init_bien         ; bueno, ya despierta
  1643. init_mal:      MOV   AH,20h            ; fallo de la controladora
  1644.                STC
  1645.                JMP   init_fin
  1646. init_bien:     MOV   AH,8              ; "leer estado interrupciones"
  1647.                CALL  fdc_write         ; enviar comando
  1648.                JC    init_fin          ; fallo
  1649.                CALL  fdc_read          ; leer ST0
  1650.                JC    init_fin          ; fallo
  1651.                MOV   DS:[42h],AL       ; guardar ST0
  1652.                PUSH  AX
  1653.                CALL  fdc_read          ; leer cilindro actual
  1654.                MOV   DS:[42h+1],AL     ; guardarlo
  1655.                POP   CX
  1656.                JC    init_fin          ; fallo
  1657.                AND   CL,0C0h
  1658.                CMP   CL,0C0h           ; ¿terminación anormal?
  1659.                JNE   init_mal          ; no es terminación anormal
  1660.                XOR   AH,AH             ; ok: el FDC detecta el fallo
  1661. init_fin:      JMP   fdc_init
  1662. init_fdc       ENDP
  1663.  
  1664. ; ------------ Resetear el FDC.
  1665.  
  1666. reset_disk     PROC
  1667.                CLI
  1668.                AND   BYTE PTR DS:[3Fh],7Fh  ; operación R/V
  1669.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1670.                MOV   AL,DS:[3Fh]
  1671.                XROL  AL,4              ; bits 7-4: motores
  1672.                AND   AL,0FBH           ; bits 3-0: unidad
  1673.                OR    AL,8              ; interrupciones ON + reset
  1674.                MOV   DX,3F2h
  1675.                OUT   DX,AL             ; hacer reset
  1676.               IFNDEF XT
  1677.                MOV   CX,3
  1678.                CALL  wait_time         ; retardo de 30-45µs
  1679.               ELSE
  1680.                CALL  retardo53         ; pequeño retardo
  1681.               ENDIF
  1682.                OR    AL,0CH
  1683.                OUT   DX,AL             ; fin del reset
  1684.                MOV   AX,9001h
  1685.                INT   15h               ; facilitar multitarea
  1686.                STI
  1687.                JC    fin_wait          ; error
  1688.                CALL  wait_int          ; esperar interrupción de disco
  1689. fin_wait:      MOV   AH,80h            ; "unidad no preparada"
  1690.                JC    exit_reset        ; hay error
  1691.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1692.                XOR   AH,AH                  ; no hay error
  1693. exit_reset:    RET
  1694. reset_disk     ENDP
  1695.  
  1696. ; ------------ Enviar comando specify obtenido de INT 1Eh al FDC.
  1697.  
  1698. send_specify   PROC
  1699.                PUSH  DS
  1700.                XOR   BX,BX
  1701.                MOV   DS,BX
  1702.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1703.                MOV   AL,3                   ; comando specify del FDC
  1704.                MOV   AH,[BX]           ; byte 0 del comando specify
  1705.                MOV   SI,AX
  1706.                MOV   AL,[BX+1]         ; byte 1 del comando specify
  1707.                MOV   DI,AX
  1708.                MOV   CH,3              ; orden de 3 bytes (SI, DI-L)
  1709.                POP   DS
  1710.                OR    BYTE PTR DS:[3Eh],80h  ; no esperar IRQ
  1711.                CALL  exec_cmd           ; mandar specify al FDC
  1712.                JMP   specify_sent
  1713. send_specify   ENDP
  1714.  
  1715. ; ------------ Esperar una interrupción de disco durante 2 segundos.
  1716.  
  1717.               IFNDEF XT
  1718.  
  1719. wait_int       PROC
  1720.                MOV   BX,3Eh            ; variable con flag de INT
  1721.                XOR   CX,CX
  1722.                CALL  wait_event        ; esperar IRQ durante 1 segundo
  1723.                JNC   wait_int_ret
  1724.                XOR   CX,CX
  1725.                CALL  wait_event        ; esperar otro segundo más
  1726. wait_int_ret:  RET
  1727. wait_int       ENDP
  1728.  
  1729.               ELSE
  1730.  
  1731. wait_int       PROC
  1732.                MOV   BX,3Eh            ; variable con flag de INT
  1733.                MOV   CX,37
  1734.                CALL  wait_event        ; esperar IRQ durante 2 seg.
  1735.                RET
  1736. wait_int       ENDP
  1737.  
  1738.               ENDIF
  1739.  
  1740. ; ------------ Devolver en AL el tipo de la unidad DL.
  1741.  
  1742. get_drive_type PROC
  1743.                CALL  peek_cmos         ; leer tipo de disqueteras
  1744.                OR    DL,DL
  1745.                JNZ   gdt_unidad_ok
  1746.                XSHR  AL,4              ; unidad A:
  1747. gdt_unidad_ok: AND   AL,0Fh
  1748.                CMP   SP,SP             ; ZF=1 -> resultado correcto
  1749.                RET
  1750. get_drive_type ENDP
  1751.  
  1752. ; ------------ Determinar la densidad del disquete.
  1753.  
  1754. detect_media   PROC
  1755.                PUSH  DX
  1756.                PUSH  CX
  1757.                PUSH  BX
  1758.                MOV   BL,r_dl
  1759.                XOR   BH,BH
  1760.                MOV   DL,BL
  1761.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1762.                MOV   AH,0
  1763.                JZ    dm_fast           ; ha sido posible obtenerlo
  1764.                JMP   dm_slow           ; usar procedimiento lento
  1765. dm_fast:       MOV   BYTE PTR DS:[BX+90h],0  ; estado físico unidad
  1766.                DEC   AX
  1767.                JNZ   dm_es_1200K?
  1768.                MOV   AL,93h            ; 360K: 360K en 360K, 250 Kbps
  1769. dm_try:        PUSH  AX
  1770.                MOV   DH,AL
  1771.                AND   DH,0C0h
  1772.                XSHR  DH,6
  1773.                CALL  set_rate          ; velocidad de transferencia DH
  1774.                POP   AX
  1775. dm_result:     MOV   DS:[BX+90h],AL    ; estado físico...
  1776.                TEST  AL,10h            ; ...¿determinado?
  1777.                JZ    dm_fails          ; aún no
  1778.                XOR   AH,AH
  1779.                JMP   dm_exit           ; sí: resultado correcto
  1780.                NOP
  1781. dm_es_1200K?:  DEC   AX
  1782.                JNZ   dm_es_720K?
  1783.                MOV   AL,0              
  1784.                CALL  read_ids          ; 1.2M: 500 kbps
  1785.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1786.                JNC   dm_result         ; sí funciona
  1787.                MOV   AL,40h
  1788.                MOV   BYTE PTR DS:[BX+90h],2
  1789.                CALL  read_ids          ; probar 300 Kbps
  1790.                MOV   AL,74h            ; indicar 360K en 1.2M
  1791.                JNC   dm_result         ; sí funciona
  1792.                MOV   AL,2              ; indicar "¿1.2M en 1.2M?"
  1793.                JMP   dm_result
  1794. dm_es_720K?:   DEC   AX
  1795.                JNZ   dm_es_1440K?
  1796.                MOV   AL,97h            ; 720K: 250 Kbps
  1797.                JMP   dm_try            ; a probar suerte
  1798. dm_es_1440K?:  DEC   AX
  1799.                JNZ   dm_es_2880K
  1800.                MOV   AL,0
  1801.                CALL  read_ids          ; 1.44M: 500 Kbps
  1802.                MOV   AL,17h            ; indicar 1.44M
  1803.                JNC   dm_result         ; sí funciona
  1804.                MOV   AL,80h
  1805.                CALL  read_ids          ; probar a 250 Kbps
  1806.                MOV   AL,97h            ; indicar 720K
  1807.                JNC   dm_result         ; sí funciona
  1808.                MOV   AL,7              ; indicar "¿1.44M?"
  1809.                JMP   dm_result
  1810. dm_es_2880K:   MOV   AL,0C0h
  1811.                CALL  read_ids          ; 2.88M: 1 Mbps
  1812.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1813.                JNC   dm_result         ; sí funciona
  1814.                MOV   AL,0
  1815.                CALL  read_ids          ; probar 500 Kbps
  1816.                MOV   AL,17h            ; indicar 1.44M
  1817.                JNC   dm_result         ; sí funciona
  1818.                MOV   AL,80h
  1819.                CALL  read_ids          ; probar 250 Kbps
  1820.                MOV   AL,97h            ; indicar 720K
  1821.                JNC   dm_result         ; sí funciona
  1822.                MOV   AL,0C7h           ; indicar "¿2.88M en 2.88M?"
  1823.                JMP   dm_result
  1824. dm_fails:      STC                     ; condición de error
  1825. dm_exit:       MOV   DS:[41h],AH       ; código de error
  1826.                POP   BX
  1827.                POP   CX
  1828.                POP   DX
  1829.                RET
  1830. dm_slow:       MOV   AL,0
  1831.                CALL  read_ids          ; probar 500 Kbps
  1832.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1833.                JNC   dm_slow_ok        ; sí funciona
  1834.                MOV   AL,40h
  1835.                MOV   BYTE PTR DS:[BX+90h],2
  1836.                CALL  read_ids          ; probar 300 Kbps
  1837.                MOV   AL,74h            ; indicar 360K en 1.2M
  1838.                JNC   dm_slow_ok        ; sí funciona
  1839.                MOV   AL,80h
  1840.                CALL  read_ids          ; probar 250 Kbps
  1841.                MOV   AL,97h            ; indicar 720K ó 360K en 360K
  1842.                JNC   dm_slow_ok        ; sí funciona
  1843.                MOV   AL,0C0h
  1844.                CALL  read_ids          ; probar 1 Mbps
  1845.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1846.                JC    dm_fails          ; no funciona
  1847. dm_slow_ok:    JMP   dm_result
  1848. detect_media   ENDP
  1849.  
  1850. ; ------------ Efectuar una lectura de ID's a velocidad AL (bits 6-7).
  1851.  
  1852. read_ids       PROC
  1853.                PUSH  BX
  1854.                PUSHF
  1855.                CLI
  1856.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1857.                POPF
  1858.                XSHR  AL,6              ; colocar bits de velocidad
  1859.                MOV   DH,AL
  1860.                CALL  set_rate          ; velocidad de transferencia DH
  1861.                MOV   DL,r_dl
  1862.                CALL  recalibrate       ; recalibrar
  1863.                JNC   read_id_try
  1864.                CALL  recalibrate       ; segundo intento
  1865.                JC    read_id_err
  1866. read_id_try:   MOV   CX,3              ; 3 intentos
  1867. read_id_retry: PUSH  CX
  1868.                MOV   DH,DL             ; en el cabezal 0 de la unidad
  1869.                MOV   DL,4Ah            ; comando de leer ID's
  1870.                MOV   SI,DX
  1871.                MOV   DL,DH
  1872.                MOV   CH,2              ; comando de 2 bytes
  1873.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1874.                CALL  exec_cmd
  1875.                JC    read_id_fails     ; fallo
  1876.                MOV   BX,42h
  1877.                MOV   CX,7
  1878.                CALL  get_results       ; leer bytes de resultados
  1879.                JC    read_id_fails
  1880.                CALL  get_bios_err      ; obtener código de error
  1881.                POP   CX
  1882.                OR    AH,AH
  1883.                JZ    read_id_ret       ; ya no hay fallo
  1884.                LOOP  read_id_retry     ; reintentar
  1885.                JMP   read_id_err       ; mala suerte
  1886. read_id_fails: POP   CX
  1887. read_id_err:   STC
  1888. read_id_ret:   POP   BX
  1889.                RET
  1890. read_ids       ENDP
  1891.  
  1892. ; ------------ Seleccionar la velocidad de transferencia adecuada.
  1893.  
  1894. select_rate    PROC
  1895.                PUSH  SI
  1896.                MOV   SI,90h
  1897.                XOR   DH,DH
  1898.                ADD   SI,DX             ; [SI] -> estado físico unidad
  1899.                MOV   DH,[SI]           ; estado físico nueva unidad
  1900.                MOV   DL,DS:[8Bh]       ; control del medio físico
  1901.                AND   DX,0C0C0h         ; aislar bits de velocidad
  1902.                CMP   DL,DH             ; ¿velocidad ya seleccionada?
  1903.                JE    selected_rate
  1904.                AND   BYTE PTR DS:[8Bh],3Fh  ; no: borrar la anterior
  1905.                OR    DS:[8Bh],DH            ; indicar la nueva
  1906.                AND   DH,0C0h
  1907.                XROL  DH,2
  1908.                CALL  set_rate          ; nueva velocidad transferencia
  1909. selected_rate: POP   SI
  1910.                MOV   DX,r_dx           ; restaurar DX
  1911.                RET
  1912. select_rate    ENDP
  1913.  
  1914. ; ------------ Establecer la velocidad de transferencia DH.
  1915.  
  1916. set_rate       PROC
  1917.                PUSH  AX
  1918.                MOV   AL,DH
  1919.                MOV   DX,3F7h      ; registro de control del disquete
  1920.                OUT   DX,AL        ; seleccionar velocidad
  1921.                POP   AX
  1922.                RET
  1923. set_rate       ENDP
  1924.  
  1925. ; ------------ Esperar que alguno de los bits a 1 de AH en el
  1926. ;              puerto DX se pongan a 0 en no más de CX 15.09 µs.
  1927.  
  1928.               IFNDEF XT
  1929.  
  1930. wait0          PROC
  1931.                PUSH  AX
  1932. wait0_do:      IN    AL,DX             ; leer del puerto E/S
  1933.                TEST  AL,AH
  1934.                JZ    wait0_end         ; bit(s) ya a 0
  1935. wait0_delay0:  IN    AL,61h
  1936.                TEST  AL,10h
  1937.                JZ    wait0_delay0      ; esperar 15.09 µs
  1938.                DEC   CX
  1939.                JZ    wait0_fail        ; timeout
  1940.                IN    AL,DX             ; volver a leer del puerto E/S
  1941.                TEST  AL,AH
  1942.                JZ    wait0_end         ; bit(s) ya a 0
  1943. wait0_delay1:  IN    AL,61h
  1944.                TEST  AL,10h
  1945.                JNZ   wait0_delay1      ; esperar 15.09 µs
  1946.                DEC   CX
  1947.                JNZ   wait0_do          ; aún no hay timeout
  1948. wait0_fail:    STC                     ; error de timeout
  1949. wait0_end:     POP   AX
  1950.                RET
  1951. wait0          ENDP
  1952.  
  1953.               ENDIF
  1954.  
  1955. ; ------------ Esperar que alguno de los bits a 1 de AH en el
  1956. ;              puerto DX se pongan a 1 en no más de CX 15.09 µs.
  1957.  
  1958.               IFNDEF XT
  1959.  
  1960. wait1          PROC
  1961.                PUSH  AX
  1962. wait1_do:      IN    AL,DX             ; leer del puerto E/S
  1963.                TEST  AL,AH
  1964.                JNZ   wait1_end         ; bit(s) ya a 1
  1965. wait1_delay0:  IN    AL,61h
  1966.                TEST  AL,10h
  1967.                JZ    wait1_delay0      ; esperar 15.09 µs
  1968.                DEC   CX
  1969.                JZ    wait1_fail        ; timeout
  1970.                IN    AL,DX             ; volver a leer del puerto E/S
  1971.                TEST  AL,AH
  1972.                JNZ   wait1_end         ; bit(s) ya a 1
  1973. wait1_delay1:  IN    AL,61h
  1974.                TEST  AL,10h
  1975.                JNZ   wait1_delay1      ; esperar 15.09 µs
  1976.                DEC   CX
  1977.                JNZ   wait1_do          ; aún no hay timeout
  1978. wait1_fail:    STC                     ; error de timeout
  1979. wait1_end:     POP   AX
  1980.                RET
  1981. wait1          ENDP
  1982.  
  1983.               ENDIF
  1984.  
  1985. ; ------------ Esperar evento durante CX 15.09 µs.
  1986.  
  1987.               IFNDEF XT
  1988.  
  1989. wait_event     PROC
  1990.                PUSH  AX
  1991. test_int:      TEST  BYTE PTR [BX],80h
  1992.                JNZ   fin_w_event       ; llegó la interrupción
  1993. w_ref1:        IN    AL,61h
  1994.                TEST  AL,10h
  1995.                JZ    w_ref1            ; esperar 15 µs
  1996.                DEC   CX
  1997.                JZ    w_event_none      ; timeout
  1998.                TEST  BYTE PTR [BX],80h
  1999.                JNZ   fin_w_event       ; llegó la interrupción
  2000. w_ref2:        IN    AL,61h
  2001.                TEST  AL,10h
  2002.                JNZ   w_ref2            ; esperar 15 µs
  2003.                DEC   CX
  2004.                JNZ   test_int          ; queda tiempo, esperar más
  2005. w_event_none:  STC                     ; no llegó la interrupción
  2006. fin_w_event:   POP   AX
  2007.                RET
  2008. wait_event     ENDP
  2009.  
  2010.               ELSE
  2011.  
  2012. wait_event     PROC
  2013.                PUSH  AX
  2014. test_55ms:     MOV   AL,DS:[6Ch]
  2015. test_int:      TEST  BYTE PTR [BX],80h
  2016.                JNZ   fin_w_event       ; llegó la interrupción
  2017. w_timer:       CMP   AL,DS:[6Ch]
  2018.                JE    test_int
  2019.                LOOP  test_55ms
  2020.                STC                     ; no llegó la interrupción
  2021. fin_w_event:   POP   AX
  2022.                RET
  2023. wait_event     ENDP
  2024.  
  2025.               ENDIF
  2026.  
  2027. ; ------------ Retardo de CX 15.09 µs aproximadamente.
  2028.  
  2029.               IFNDEF XT
  2030.  
  2031. wait_time      PROC
  2032.                PUSH  AX
  2033. wait_ref_h:    IN    AL,61h
  2034.                TEST  AL,10h            ; esperar ciclo de refresco
  2035.                JZ    wait_ref_h        ; de memoria (15,09 µs)
  2036.                DEC   CX
  2037.                JZ    wait_time_fin     ; fin de la espera
  2038. wait_ref_l:    IN    AL,61h
  2039.                TEST  AL,10h            ; esperar ciclo de refresco
  2040.                JNZ   wait_ref_l        ; de memoria (15,09 µs)
  2041.                DEC   CX
  2042.                JNZ   wait_ref_h        ; completar espera
  2043. wait_time_fin: POP   AX
  2044.                RET
  2045. wait_time      ENDP
  2046.  
  2047.               ENDIF
  2048.  
  2049. ; ------------ Simular la lectura del registro 10h de la CMOS, para
  2050. ;              el tipo de las disqueteras.
  2051.  
  2052. peek_cmos      PROC
  2053.                MOV   AL,CS:tipo_drvs   ; nuestro tipo simulado
  2054.                RET
  2055. peek_cmos      ENDP
  2056.  
  2057. ; ------------ Esperar exactamente CX milisegundos.
  2058.  
  2059.               IFDEF  XT
  2060.  
  2061. retardo        PROC
  2062.                PUSHF
  2063.                XPUSH <AX, BX, CX, DX>
  2064. retarda_mas:   CMP   CX,54             ; como máximo 54 ms cada vez
  2065.                JBE   retarda_fin
  2066.                PUSH  CX
  2067.                MOV   AX,54
  2068.                CALL  rt_ax
  2069.                POP   CX
  2070.                SUB   CX,54
  2071.                JMP   retarda_mas
  2072. retarda_fin:   MOV   AX,CX
  2073.                CALL  rt_ax
  2074.                XPOP  <DX, CX, BX, AX>
  2075.                POPF
  2076.                RET
  2077.  
  2078. rt_ax:         PUSH  CX
  2079.                MOV   DX,1000           ; retardo de hasta 54 ms
  2080.                MUL   DX
  2081.                MUL   CS:tbase
  2082.                MOV   CX,54925
  2083.                DIV   CX                ; AX = contador iteraciones
  2084.                MOV   CX,AX
  2085.                EVEN                    ; forzar alineamiento
  2086. retarda:       DEC   CX
  2087.                JMP   SHORT $+2
  2088.                JNZ   retarda
  2089.                POP   CX
  2090.                RET
  2091. retardo        ENDP
  2092.  
  2093. retardo53      PROC
  2094.                MOV   CX,CS:tbase
  2095.                MOV   CL,CH
  2096.                MOV   CH,0
  2097.                SHR   CX,1
  2098.                SHR   CX,1
  2099.                EVEN                    ; forzar alineamiento
  2100. retarda_res:   DEC   CX
  2101.                JMP   SHORT $+2
  2102.                JNZ   retarda_res       ; pausa de 53 µs
  2103.                RET
  2104. retardo53      ENDP
  2105.  
  2106.               ENDIF
  2107.  
  2108. ; ------------ Datos.
  2109.  
  2110. tipo_drvs      DB    0    ; tipo de disqueteras (definido al instalar)
  2111.               IFDEF  XT
  2112. tbase          DW    ?    ; cte de tiempo para bucles de retardo
  2113.               ENDIF
  2114.  
  2115.                ; --- Tabla de saltos a las funciones
  2116.  
  2117. tab_jmp        DW    reset, get_status
  2118.                DW    read_wr_verify, read_wr_verify, read_wr_verify
  2119.                DW    format_track, get_drv_param, get_disk_type
  2120.                DW    detect_change, set_type_fmt, set_media_fmt
  2121.  
  2122.                ; --- Tabla de tamaños en sectores y cilindros
  2123.  
  2124. tab_disksize   DW     9 + 39 * 256  ; 360K
  2125.                DW    15 + 79 * 256  ; 1.2M
  2126.                DW     9 + 79 * 256  ; 720K
  2127.                DW    18 + 79 * 256  ; 1.44M
  2128.                DW    36 + 79 * 256  ; 2.88M
  2129.  
  2130.                ; --- Tablas de parámetros de disco (sintaxis INT 1Eh)
  2131.  
  2132. tab_ptr_1e     DW    t360in360, t1200, t720, t1440, t2880
  2133.  
  2134.                ; Bytes de esta tabla, similar a la de INT 1Eh:
  2135.                ;
  2136.                ;     0) byte 1 para 'Specify' (step rate-head unload)
  2137.                ;     1) byte 2 para 'Specify' (head load-modo DMA)
  2138.                ;     2) tics de reloj hasta detención del motor
  2139.                ;     3) tamaño de sector (0-128, 1-256, 2-512, ...)
  2140.                ;     4) sectores por pista
  2141.                ;     5) GAP3 para lectura/escritura
  2142.                ;     6) longitud concreta de sector si tamaño=0
  2143.                ;     7) GAP3 para formateo
  2144.                ;     8) byte de relleno al formatear
  2145.                ;     9) tiempo de estabilización del cabezal en ms
  2146.                ;    10) tiempo aceleración motor, en 1/8 segundos
  2147.                ;    11) número de cilindros menos uno
  2148.                ;    12) velocidad de transferencia (en bits 6-7)
  2149.  
  2150. t360in360      DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 360K
  2151.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  2152.                DB    008h, 027h, 080h
  2153. t1200          DB    0DFh, 002h, 025h, 002h, 00Fh   ; 1.2M
  2154.                DB    01Bh, 0FFh, 054h, 0F6h, 00Fh
  2155.                DB    008h, 04Fh, 000h
  2156. t720           DB    0DFh, 002h, 025h, 002h, 009h   ; 720K
  2157.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  2158.                DB    008h, 04Fh, 080h
  2159. t1440          DB    0BFh, 002h, 025h, 002h, 012h   ; 1.44M
  2160.                DB    01Bh, 0FFh, 06Ch, 0F6h, 00Fh
  2161.                DB    008h, 04Fh, 000h
  2162. t360en1200     DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 1.2M
  2163.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  2164.                DB    008h, 027h, 040h
  2165. t2880          DB    0AFh, 002h, 025h, 002h, 024h   ; 2.88M
  2166.                DB    01Bh, 0FFh, 050h, 0F6h, 00Fh
  2167.                DB    008h, 04Fh, 0C0h
  2168.  
  2169.                ; --- Fin del área residente para INT 40h
  2170.  
  2171. fin_residente  EQU   $
  2172.  
  2173. bytes_resid    EQU   fin_residente-ini_residente
  2174.  
  2175. ; ------------ Rutina de gestión de INT 13h (si se necesita). Se llama
  2176. ;              a la INT 40h de manera que esta última no devuelva
  2177. ;              nunca errores de frontera de DMA, para lo que emplea un
  2178. ;              buffer auxiliar de 512 bytes para transferir el sector
  2179. ;              que cruzaría la frontera. En la función de formateo, al
  2180. ;              acceder a la primera pista del disco se invoca primero
  2181. ;              la interrupción original para que el DOS (cargado antes
  2182. ;              que este programa) se entere del cambio de soporte.
  2183.  
  2184. ges_int13      PROC
  2185.                STI
  2186.                CMP   DL,80h
  2187.                JB    floppy
  2188.                JMP   CS:ant_int13
  2189. floppy:        CMP   AH,2
  2190.                JB    floppy_bios
  2191.                CMP   AH,5
  2192.                JE    test_format
  2193.                JB    test_rwv
  2194. floppy_bios:   INT   40h               ; función sin problemas de DMA
  2195.                RETF  2
  2196. ges_int13      ENDP
  2197.  
  2198. test_format    PROC
  2199.                XPUSH <DS, ES, BX>
  2200.                XPUSHA
  2201.                PUSH  DX
  2202.                OR    DH,CH
  2203.                POP   DX
  2204.                JNZ   skip_aviso        ; no es pista y cabezal 0
  2205.                CMP   CL,0FFh
  2206.                JE    skip_aviso        ; 2M 3.0 simula el cambio
  2207.                XPUSHA
  2208.                PUSHF                   ; formatear con INT 13h para
  2209.                CALL  CS:ant_int13      ; avisar al DOS del nuevo disco
  2210.                XPOPA
  2211. skip_aviso:    MOV   DI,CS:pbuffer
  2212.                MOV   SI,BX
  2213.                PUSH  ES
  2214.                POP   DS
  2215.                PUSH  CS
  2216.                POP   ES
  2217.                MOV   CX,256
  2218.                CLD
  2219.                REP   MOVSW             ; datos de formateo al buffer
  2220.                XPOPA                   ; auxiliar
  2221.                MOV   BX,CS:pbuffer
  2222.                INT   40h               ; formateo
  2223.                XPOP  <BX, ES, DS>      ; restaurar registros iniciales
  2224.                RETF  2
  2225. test_format    ENDP
  2226.  
  2227. test_rwv       PROC                    ; para Read/Write/Verify
  2228.                MOV   CS:funcion,AH
  2229.                MOV   CS:nsects,AL
  2230.                XPUSH <SI, DI>
  2231.                XPUSH <AX, DX>
  2232.                MOV   AX,ES
  2233.                MOV   DX,16
  2234.                MUL   DX
  2235.                ADD   AX,BX
  2236.                NEG   AX                ; AX = bytes hasta frontera DMA
  2237.                XSHR  AX,9
  2238.                MOV   SI,AX             ; sectores antes frontera
  2239.                XPOP  <DX, AX>
  2240.                PUSH  AX
  2241.                MOV   AH,0
  2242.                MOV   DI,AX
  2243.                POP   AX
  2244.                CMP   SI,DI
  2245.                JBE   trwv_no_sobra
  2246.                MOV   SI,DI
  2247. trwv_no_sobra: SUB   DI,SI             ; sectores+1 tras frontera
  2248.                JZ    trwv_1ok
  2249.                PUSH  CX
  2250.                MOV   CX,SI
  2251.                MOV   AL,CL             ; AL sectores antes de frontera
  2252.                POP   CX
  2253. trwv_1ok:      AND   AL,AL
  2254.                JZ    trwv_1cruza       ; primer sector cruza frontera
  2255.                INT   40h
  2256.                PUSHF
  2257.                JNC   trwv_cont         ; sin fallo E/S
  2258. trwv_exit:     JMP   trwv_ret
  2259. trwv_cont:     AND   DI,DI
  2260.                JZ    trwv_exit         ; se acabó
  2261.                POPF
  2262. trwv_1cruza:   CMP   CS:funcion,3      ; ¿escritura?
  2263.                JNE   trwv_sectdma
  2264.                XPUSHA
  2265.                XPUSH <DS, ES>
  2266.                XSHL  SI,9              ; sectores transferidos * 512
  2267.                ADD   SI,BX
  2268.                MOV   DI,CS:pbuffer
  2269.                PUSH  ES
  2270.                POP   DS
  2271.                PUSH  CS
  2272.                POP   ES
  2273.                MOV   CX,256
  2274.                CLD
  2275.                REP   MOVSW             ; sector conflictivo a través
  2276.                XPOP  <ES, DS>          ; de buffer auxiliar
  2277.                XPOPA
  2278. trwv_sectdma:  XPUSH <ES, BX, CX>
  2279.                PUSH  CS
  2280.                POP   ES
  2281.                MOV   BX,CS:pbuffer     ; ES:BX buffer auxiliar
  2282.                MOV   AH,CS:funcion
  2283.                MOV   AL,1              ; un sector
  2284.                ADD   CX,SI             ; nuevo sector inicial
  2285.                INT   40h
  2286.                XPOP  <CX, BX, ES>
  2287.                PUSHF
  2288.                JC    trwv_ret          ; fallo E/S
  2289.                CMP   CS:funcion,2      ; ¿lectura?
  2290.                JNE   trwv_tras?
  2291.                XPUSHA
  2292.                XPUSH <DS, ES>
  2293.                XSHL  SI,9              ; sectores transferidos * 512
  2294.                MOV   DI,SI
  2295.                ADD   DI,BX
  2296.                MOV   SI,CS:pbuffer
  2297.                PUSH  CS
  2298.                POP   DS
  2299.                MOV   CX,256
  2300.                CLD
  2301.                REP   MOVSW             ; sector conflictivo a través
  2302.                XPOP  <ES, DS>          ; de buffer auxiliar
  2303.                XPOPA
  2304. trwv_tras?:    MOV   AL,CS:nsects      ; sectores transferidos
  2305.                DEC   DI
  2306.                JZ    trwv_ret          ; no queda nada tras frontera
  2307.                POPF
  2308.                XPUSH <BX, CX>
  2309.                INC   SI
  2310.                ADD   CX,SI             ; nuevo sector inicial
  2311.                XSHL  SI,9              ; sectores transferidos * 512
  2312.                ADD   BX,SI
  2313.                MOV   AX,DI             ; sectores restantes
  2314.                MOV   AH,CS:funcion
  2315.                INT   40h
  2316.                XPOP  <CX, BX>
  2317.                MOV   AL,CS:nsects      ; número sectores transferidos
  2318.                PUSHF
  2319. trwv_ret:      POPF
  2320.                XPOP  <DI, SI>
  2321.                RETF  2
  2322. test_rwv       ENDP
  2323.  
  2324. funcion        DB    ?
  2325. nsects         DB    ?
  2326. pbuffer        DW    buffer_io
  2327.  
  2328.                EVEN
  2329. buffer_io      EQU   $
  2330.  
  2331.  
  2332. ; *****************************
  2333. ; *                           *
  2334. ; *   I N S T A L A C I O N   *
  2335. ; *                           *
  2336. ; *****************************
  2337.  
  2338. main           PROC
  2339.                ADD   SP,2              ; quitar dirección de retorno
  2340.                XPUSH <AX, BX, CX, DX, SI, DI, BP, DS, ES>
  2341.                PUSH  CS
  2342.                POP   DS
  2343.                MOV   WORD PTR interrupcion,531Eh  ; opcode PUSH DS,BX
  2344.                MOV   BYTE PTR interrupcion+2,0BBh ; opcode MOV BX,??
  2345.                PUSH  CS
  2346.                POP   ES
  2347.                CALL  inic_general      ; inicializar ciertas variables
  2348.                CALL  analiza_equipo
  2349.                PUSH  ES                ; *
  2350.                MOV   BX,pcab_pet_segm
  2351.                MOV   ES,BX
  2352.                MOV   BX,pcab_pet_desp
  2353.                LES   BX,ES:[BX+12h]    ; apuntar a los parámetros
  2354.                CALL  salta_nombre
  2355.                LEA   BP,parametros
  2356.                CALL  obtener_param
  2357.                POP   ES                ; *
  2358.                CALL  set_params        ; actualizar tipo de unidades
  2359.                CMP   param_13,ON
  2360.                JNE   int_ok            ; no es parámetro /13
  2361.                AND   accion,NOT I40
  2362. int_ok:        CALL  valida_drives     ; asegurar que hay unidades
  2363.                TEST  error,0FFFFh
  2364.                JNZ   exit_ins
  2365.                CALL  hay2m?
  2366.                JC    no_2m
  2367.                OR    error,ERR_HAY2M   ; 2M ó 2MX residente
  2368.                JMP   exit_ins
  2369. no_2m:         TEST  accion,I40        ; ¿soporta INT 40h el sistema?
  2370.                JNZ   i40_ok            ; en efecto
  2371.                CALL  set_i13           ; añadir soporte vía INT 13h
  2372. i40_ok:       IFDEF  XT
  2373.                CALL  cte_tiempos
  2374.                MOV   tbase,AX
  2375.                CALL  init_vars
  2376.               ENDIF
  2377.                CALL  mx_get_handle     ; obtener entrada Multiplex
  2378.                JNC   handle_ok
  2379.                OR    error,MX64FULL    ; no quedan entradas
  2380.                JMP   exit_ins
  2381. handle_ok:     MOV   multiplex_id,AH   ; entrada multiplex para 2M
  2382.                CALL  preservar_ints    ; tomar nota de vectores
  2383.                MOV   DI,100h           ; ORG 0 (compensar COM)
  2384.                CALL  activar_ints      ; interceptar vectores
  2385.                LEA   DI,ptr_dev_info
  2386.                CALL  set_dev_params    ; establecer tipo unidades DOS
  2387.               IFNDEF XT
  2388.                CALL  setup_cmos        ; ajustar byte cmos
  2389.               ENDIF
  2390. exit_ins:      CALL  info
  2391.                MOV   BX,pcab_pet_segm
  2392.                MOV   ES,BX
  2393.                MOV   BX,pcab_pet_desp
  2394.                MOV   WORD PTR ES:[BX+3],100h ; indicar retorno correcto
  2395.                MOV   AX,longitud_total
  2396.                MOV   CL,4
  2397.                SHL   AX,CL
  2398.                TEST  error,0FFFFh
  2399.                JZ    exit_ok
  2400.                MOV   WORD PTR ES:[BX+14],0   ; OFFSET 0: no quedará
  2401.                MOV   WORD PTR ES:[BX+16],CS  ; instalado en memoria
  2402.                JMP   exit_interr
  2403. exit_ok:       MOV   WORD PTR ES:[BX+14],AX  ; OFFSET al último byte residente
  2404.                MOV   WORD PTR ES:[BX+16],CS
  2405. exit_interr:   XPOP  <ES, DS, BP, DI, SI, DX, CX, BX, AX>
  2406.                RETF
  2407. main           ENDP
  2408.  
  2409. ;*********************************************************
  2410. ;*                                                       *
  2411. ;*  SUBRUTINAS DE PROPOSITO GENERAL PARA LA INSTALACION  *
  2412. ;*                                                       *
  2413. ;*********************************************************
  2414.  
  2415.                INCLUDE 2MUTIL.INC
  2416.  
  2417. salta_nombre   PROC                    ; saltar nombre del driver en
  2418.                MOV   AL,ES:[BX]        ; línea de órdenes del CONFIG
  2419.                INC   BX
  2420.                CMP   AL,' '
  2421.                JE    fin_nombre
  2422.                CMP   AL,9
  2423.                JE    fin_nombre
  2424.                CMP   AL,0Dh
  2425.                JE    fin_nombre
  2426.                CMP   AL,0Ah
  2427.                JE    fin_nombre
  2428.                AND   AL,AL
  2429.                JZ    fin_nombre
  2430.                JMP   salta_nombre
  2431. fin_nombre:    RET
  2432. salta_nombre   ENDP
  2433.  
  2434. ; ------------ Establecer tipo disqueteras (según BIOS o parámetros).
  2435.  
  2436. set_params     PROC
  2437.                PUSH  ES
  2438.                MOV   AX,tipo_A
  2439.                CMP   AL,-1
  2440.                JNE   ta_calc           ; A: definida por el usuario
  2441.                MOV   DL,0
  2442.                CALL  tipo_disco
  2443.                MOV   AL,BL
  2444. ta_calc:       AND   tipo_drvs,0Fh
  2445.                MOV   CL,4
  2446.                SHL   AL,CL
  2447.                OR    tipo_drvs,AL      ; tipo A: en nibble alto
  2448.                MOV   AX,tipo_B
  2449.                CMP   AL,-1             ; B: definida por el usuario
  2450.                JNE   tb_calc
  2451.                MOV   DL,1
  2452.                CALL  tipo_disco
  2453.                MOV   AL,BL
  2454. tb_calc:       AND   tipo_drvs,0F0h
  2455.                OR    tipo_drvs,AL      ; tipo B: en nibble bajo
  2456.                POP   ES
  2457.                RET
  2458. set_params     ENDP
  2459.  
  2460. ; ------------ Asegurar que se conoce el tipo de las unidades.
  2461.  
  2462. valida_drives  PROC
  2463.                MOV   AL,tipo_drvs
  2464.                AND   AL,AL
  2465.                JNZ   drvs_ok
  2466.                OR    error,ERR_MALDRV
  2467. drvs_ok:       RET
  2468. valida_drives  ENDP
  2469.  
  2470. ; ------------ Código ejecutado desde la línea de comandos.
  2471.  
  2472. inicio         PROC  FAR
  2473.                MOV   AX,_PRINCIPAL
  2474.                MOV   DS,AX
  2475.                LEA   BP,parametros
  2476.                MOV   BX,81h
  2477.                CALL  obtener_param          ; procesar parámetros
  2478.                PUSH  DS
  2479.                POP   ES
  2480.                CALL  residente?
  2481.                JC    dos_info
  2482.               IFDEF  XT
  2483.                CALL  cte_tiempos
  2484.                PUSH  DS
  2485.                MOV   DS,tsr_seg
  2486.                MOV   tbase,AX
  2487.                POP   DS
  2488.               ENDIF
  2489.                CMP   param_ayuda,ON
  2490.                JE    dos_info
  2491.                LEA   DX,info_ins_txt
  2492.                CALL  print
  2493.                JMP   dos_exit
  2494. dos_info:      LEA   DX,info_txt
  2495.                CALL  print
  2496.                JNC   dos_exit
  2497.                LEA   DX,limpia_txt     ; se pulsó ESC en la ayuda
  2498.                CALL  print
  2499. dos_exit:      MOV   AX,4C00h
  2500.                INT   21h               ; final normal
  2501. inicio         ENDP
  2502.  
  2503. ; ------------ Inicializar ciertas variables.
  2504.  
  2505. inic_general   PROC
  2506.                MOV   AX,(bytes_resid+15)/16
  2507.                MOV   longitud_total,AX ; memoria necesaria
  2508.                MOV   segmento_real,CS  ; anotar segmento del bloque
  2509.                MOV   offset_real,0     ; ídem con el offset
  2510.                RET
  2511. inic_general   ENDP
  2512.  
  2513. ; ------------ Comprobar que la configuración es la adecuada. Para
  2514. ;              saber si la INT 13h de este ordenador acaba llamando a
  2515. ;              la INT 40h, se desvía la INT 40h y se provoca un inocuo
  2516. ;              reset de disquetes vía INT 13h para comprobar si pasa
  2517. ;              por la INT 40h.
  2518.  
  2519. analiza_equipo PROC
  2520.                PUSH  ES
  2521.                CALL  testAT
  2522.                MOV   AX,ERR_TIPOPC
  2523.               IFNDEF XT
  2524.                JC    cod_err_ok        ; no es AT o superior
  2525.               ELSE
  2526.                JNC   cod_err_ok        ; no es PC/XT
  2527.               ENDIF
  2528.                CALL  test_i40
  2529.                XOR   AX,AX
  2530. cod_err_ok:    OR    error,AX
  2531.                POP   ES
  2532.                RET
  2533. analiza_equipo ENDP
  2534.  
  2535.                ; --- Comprobar si la INT 40h está en uso
  2536.  
  2537. test_i40:      XPUSH <DS, ES>          ; *
  2538.                MOV   AX,3540h
  2539.                INT   21h
  2540.                XPUSH <ES, BX>          ; vector de INT 40h original
  2541.                LEA   DX,i40_aux
  2542.                MOV   AX,2540h
  2543.                INT   21h               ; establecer nueva INT 40h
  2544.                XOR   AX,AX
  2545.                MOV   DL,0
  2546.                INT   13h               ; reset de disco
  2547.                XPOP  <DX, DS>
  2548.                MOV   AX,2540h
  2549.                INT   21h               ; restaurar INT 40h original
  2550.                XPOP  <ES, DS>          ; *
  2551.                RET
  2552.  
  2553. i40_aux        PROC
  2554.                OR    CS:accion,I40     ; sí utilizada INT 40h
  2555.                IRET                    ; desde la INT 13h
  2556. i40_aux        ENDP
  2557.  
  2558.                ; ----- Detectar 286 ó superior.
  2559.  
  2560. testAT         PROC
  2561.                PUSHF
  2562.                POP   AX
  2563.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  2564.                PUSH  AX            ; del registro de estado
  2565.                POPF
  2566.                PUSHF
  2567.                POP   AX
  2568.                AND   AH,0F0h
  2569.                CMP   AH,0F0h
  2570.                JE    testedAT
  2571.                STC
  2572. testedAT:      CMC                 ; CF = 0 en AT y 1 en PC/XT
  2573.                RET
  2574. testAT         ENDP
  2575.  
  2576. ; ------------ Desviar también INT 13h ya que en esta máquina el
  2577. ;              gestor de INT 13h no invoca la INT 40h.
  2578.  
  2579. set_i13        PROC
  2580.                INC   offsets_ints      ; usado un vector más
  2581.                INC   BYTE PTR tabla_vectores-1
  2582.                MOV   AX,CS
  2583.                MOV   CX,16
  2584.                MUL   CX
  2585.                ADD   AX,pbuffer
  2586.                ADC   DX,0              ; DX:AX = dirección 20 bits
  2587.                MOV   CX,DX
  2588.                PUSH  AX
  2589.                ADD   AX,511            ; buffer para el mayor sector
  2590.                ADC   DX,0
  2591.                POP   AX
  2592.                CMP   DX,CX
  2593.                JE    dma_ok
  2594.                NEG   AX
  2595.                ADD   pbuffer,AX        ; saltar hasta próxima frontera
  2596.                OR    accion,BUFFERPLUS
  2597. dma_ok:        MOV   AX,pbuffer
  2598.                ADD   AX,512
  2599.                SUB   AX,OFFSET ges_int13
  2600.                ADD   AX,15
  2601.                MOV   CL,4
  2602.                SHR   AX,CL
  2603.                ADD   longitud_total,AX ; es necesaria más memoria
  2604.                RET
  2605. set_i13        ENDP
  2606.  
  2607. ; ------------ Devolver CF=0 si 2M o 2MX están instalados o se ha
  2608. ;              cargado el código 2M en modo SuperBOOT (en este último
  2609. ;              caso, la rutina funciona aunque QEMM modifique de modo
  2610. ;              temporal el límite de memoria a casi un mega en la
  2611. ;              llamada a INT 12h).
  2612.  
  2613. hay2m?         PROC
  2614.                PUSH  ES
  2615.                LEA   SI,id_2m          ; identificación del programa
  2616.                MOV   CX,id_2m_tam
  2617.                MOV   AX,1492h
  2618.                MOV   ES,AX
  2619.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  2620.                CALL  mx_find_tsr       ; buscar si está en memoria
  2621.                JNC   hay2m?_ret
  2622.                LEA   SI,id_2mx         ; identificación del programa
  2623.                MOV   CX,id_2mx_tam
  2624.                CALL  mx_find_tsr
  2625.                JNC   hay2m?_ret
  2626.                INT   12h               ; tamaño memoria convencional
  2627.                MOV   BX,640
  2628.                CMP   AX,256
  2629.                JB    base_sc_ok        ; dato extraño
  2630.                CMP   AX,640
  2631.                JA    base_sc_ok        ; dato extraño
  2632.                MOV   BX,AX
  2633. base_sc_ok:    MOV   AX,BX
  2634.                ADD   AX,127            ; redondeo
  2635.                MOV   CL,7
  2636.                SHR   AX,CL
  2637.                SHL   AX,CL             ; hacia frontera de 128K
  2638.                MOV   CX,AX
  2639.                SUB   CX,BX             ; buscar en área posible
  2640.                DEC   AX
  2641.                MOV   BX,64
  2642.                MUL   BX                ; AX = segmento de SuperBOOT
  2643.                CLD
  2644. scan_boot:     MOV   ES,AX
  2645.                MOV   DI,6
  2646.                LEA   SI,id_boot
  2647.                PUSH  CX                ; *
  2648.                MOV   CX,id_boot_tam
  2649.                REP   CMPSB
  2650.                POP   CX                ; *
  2651.                JE    hay2m?_ret        ; CF = 0 -> 2M SuperBOOT
  2652.                SUB   AX,64
  2653.                LOOPNZ scan_boot        ; buscar 1K más abajo
  2654. nohaysb_ret:   STC
  2655. hay2m?_ret:    POP   ES
  2656.                RET
  2657. hay2m?         ENDP
  2658.  
  2659. ; ------------ Informar al usuario.
  2660.  
  2661. info           PROC
  2662.                TEST  error,0FFFFh
  2663.                JZ    info_mas
  2664.                LEA   DX,no_inst_txt
  2665.                CALL  print
  2666.                LEA   DX,mal_cpu_txt
  2667.                TEST  error,ERR_TIPOPC
  2668.                JNZ   print_err
  2669.                LEA   DX,hay2m_txt
  2670.                TEST  error,ERR_HAY2M
  2671.                JNZ   print_err
  2672.                LEA   DX,null_drv_txt
  2673.                TEST  error,ERR_MALDRV
  2674.                JNZ   print_err
  2675.                LEA   DX,err_syntax_txt
  2676.                TEST  error,ERRSINTAX
  2677.                JNZ   print_err
  2678.                LEA   DX,err_mx64full
  2679.                TEST  error,MX64FULL
  2680.                JZ    fin_info
  2681. print_err:     CALL  print
  2682.                RET
  2683. info_mas:      LEA   DX,instalado_txt
  2684.                CALL  print
  2685.                CALL  info_drives
  2686.                TEST  accion,BUFFERPLUS
  2687.                JZ    fin_info
  2688.                LEA   DX,dma_cross_txt
  2689.                CALL  print
  2690. fin_info:      RET
  2691. info           ENDP
  2692.  
  2693.                ; --- Informar de las unidades controladas.
  2694.  
  2695. info_drives    PROC
  2696.                MOV   DL,0
  2697.                CALL  tipo_disco
  2698.                AND   BL,BL
  2699.                JZ    info_B
  2700.                MOV   BH,0
  2701.                DEC   BX
  2702.                SHL   BX,1
  2703.                LEA   DX,a_txt          ; "A:"
  2704.                CALL  print
  2705.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2706.                CALL  print
  2707. info_B:        MOV   DL,1
  2708.                CALL  tipo_disco
  2709.                AND   BL,BL
  2710.                JZ    info_exit
  2711.                MOV   BH,0
  2712.                DEC   BX
  2713.                SHL   BX,1
  2714.                LEA   DX,b_txt          ; "B:"
  2715.                CALL  print
  2716.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2717.                CALL  print
  2718. info_exit:     LEA   DX,i40_txt
  2719.                TEST  accion,I40
  2720.                JNZ   imodo_ok
  2721.                LEA   DX,i13_txt
  2722. imodo_ok:      CALL  print             ; modo de instalación
  2723.                RET
  2724. info_drives    ENDP
  2725.  
  2726. ; ------------ Calcular la constante de retardo básica para perder
  2727. ;              exactamente 54,925 ms. Con una regla de 3 se podrá
  2728. ;              después aplicar para hacer retardos de milisegundos.
  2729.  
  2730.               IFDEF  XT
  2731.  
  2732. cte_tiempos    PROC
  2733.                XPUSH <DS, ES, BX, CX, DX>
  2734.                MOV   AX,3508h
  2735.                INT   21h
  2736.                XPUSH <ES, BX>          ; preservar vector de INT 8
  2737.                PUSH  DS
  2738.                MOV   AX,40h
  2739.                MOV   DS,AX
  2740.                MOV   AL,DS:[6Ch]
  2741. espera_i8:     CMP   AL,DS:[6Ch]
  2742.                JE    espera_i8         ; esperar INT 8 ... para que no
  2743.                POP   DS
  2744.                LEA   DX,i8_crono       ; venga otra en un buen rato...
  2745.                MOV   AX,2508h
  2746.                INT   21h               ; nueva rutina de INT 8
  2747.                IN    AL,21h
  2748.                PUSH  AX                ; preservar estado de IRQ's
  2749.                MOV   AL,11111110b
  2750.                OUT   21h,AL            ; permitir sólo IRQ0
  2751.                MOV   AH,0              ; fase
  2752.                MOV   CX,0              ; contador
  2753.                MOV   BX,CX             ; seguiría a 0 si fallara
  2754.                EVEN                    ; forzar alineamiento
  2755. cuenta_iter:   DEC   CX                ; <─┐ bucle básico de retardo
  2756.                JMP   SHORT $+2         ;   │
  2757.                JNZ   cuenta_iter       ; <─┘ lo interrumpirá INT 8
  2758.                POP   AX                ; anterior estado de IRQ's
  2759.                OUT   21h,AL
  2760.                XPOP  <DX, DS>
  2761.                PUSH  BX                ; valor real contado
  2762.                MOV   AX,2508h          ; restaurar vector de INT 8
  2763.                INT   21h
  2764.                POP   AX                ; (65536-AX) vueltas en 54,9 ms
  2765.                NEG   AX                ; constante de retardo básica
  2766.                XPOP  <DX, CX, BX, ES, DS>
  2767.                RET
  2768. i8_crono:      INC   AH                ; nueva INT 8 que interrumpe
  2769.                CMP   AH,1              ; el bucle de retardo
  2770.                JE    fase1
  2771.                CMP   AH,2
  2772.                JE    fase2
  2773. i8_exit:       MOV   AL,20h
  2774.                OUT   20h,AL
  2775.                IRET
  2776. fase1:         MOV   CX,0              ; sincronizar con el reloj
  2777.                JMP   i8_exit
  2778. fase2:         MOV   BX,CX             ; anotar constante de retardo
  2779.                MOV   CX,1              ; forzar fin del bucle
  2780.                JMP   i8_exit
  2781. cte_tiempos    ENDP
  2782.  
  2783.               ENDIF
  2784.  
  2785. ; ------------ Inicializar variables en el área de datos de la BIOS.
  2786.  
  2787.               IFDEF  XT
  2788.  
  2789. init_vars      PROC
  2790.                PUSH  DS
  2791.                MOV   AX,40h
  2792.                MOV   DS,AX
  2793.                AND   BYTE PTR DS:[3Eh],01110000b
  2794.                MOV   BYTE PTR DS:[8Bh],00000000b
  2795.                MOV   DX,3F7h
  2796.                MOV   AL,0
  2797.                OUT   DX,AL
  2798.                MOV   BYTE PTR DS:[8Fh],01110111b
  2799.                MOV   BYTE PTR DS:[90h],0
  2800.                MOV   BYTE PTR DS:[91h],0
  2801.                POP   DS
  2802.                RET
  2803. init_vars      ENDP
  2804.  
  2805.               ENDIF
  2806.  
  2807. ; ------------ Ajustar byte CMOS con el tipo de las disqueteras.
  2808.  
  2809.               IFNDEF  XT
  2810.  
  2811. setup_cmos     PROC
  2812.                CMP   param_c,ON
  2813.                JNE   modifica_cmos
  2814.                RET                     ; con /C no alterar CMOS.
  2815. modifica_cmos: MOV   AL,2Eh
  2816.                CALL  read_cmos
  2817.                MOV   BH,AL
  2818.                MOV   AL,2Fh
  2819.                CALL  read_cmos
  2820.                MOV   BL,AL             ; BX = checksum
  2821.                MOV   AL,10h
  2822.                CALL  read_cmos         ; byte CMOS tipo disqueteras
  2823.                SUB   AL,tipo_drvs      ; diferencia relativa
  2824.                CBW
  2825.                SUB   BX,AX             ; nuevo checksum
  2826.                MOV   AL,10h
  2827.                MOV   AH,tipo_drvs
  2828.                CALL  write_cmos        ; actualizar byte de tipo
  2829.                MOV   AL,2Eh
  2830.                MOV   AH,BH
  2831.                CALL  write_cmos
  2832.                MOV   AL,2Fh
  2833.                MOV   AH,BL
  2834.                CALL  write_cmos        ; y checksum
  2835.                RET
  2836. setup_cmos     ENDP
  2837.  
  2838. read_cmos      PROC
  2839.                CLI
  2840.                OUT   70h,AL
  2841.                JMP   SHORT $+2
  2842.                JMP   SHORT $+2
  2843.                IN    AL,71h
  2844.                STI
  2845.                RET
  2846. read_cmos      ENDP
  2847.  
  2848. write_cmos     PROC
  2849.                CLI
  2850.                OUT   70h,AL
  2851.                JMP   SHORT $+2
  2852.                JMP   SHORT $+2
  2853.                MOV   AL,AH
  2854.                OUT   71h,AL
  2855.                STI
  2856.                RET
  2857. write_cmos     ENDP
  2858.  
  2859.               ENDIF
  2860.  
  2861. ; ************ Datos no residentes para la instalación
  2862.  
  2863. ON             EQU   1                 ; constantes booleanas
  2864. OFF            EQU   0
  2865.  
  2866. parametros     LABEL BYTE
  2867.  
  2868.                DB    "?",0
  2869.                DW    param_ayuda
  2870.                DB    ON
  2871.  
  2872.                DB    "/?",0
  2873.                DW    param_ayuda
  2874.                DB    ON
  2875.  
  2876.                DB    "/H",0
  2877.                DW    param_ayuda
  2878.                DB    ON
  2879.  
  2880.                DB    "/13",0
  2881.                DW    param_13
  2882.                DB    ON
  2883.  
  2884.                DB    "/C",0
  2885.                DW    param_c
  2886.                DB    ON
  2887.  
  2888.                DB    "A",1
  2889.                DW    0, 5
  2890.                DW    tipo_A
  2891.                DW    param_unidad
  2892.                DB    ON
  2893.  
  2894.                DB    "B",1
  2895.                DW    0, 5
  2896.                DW    tipo_B
  2897.                DW    param_unidad
  2898.                DB    ON
  2899.  
  2900.                DB    "/I",0
  2901.                DW    param_i
  2902.                DB    ON
  2903.  
  2904.                DB    0                 ; fin de la tabla
  2905.  
  2906.  
  2907. param_ayuda    DB    OFF               ; a ON si se solicita ayuda
  2908. param_c        DB    OFF               ; a ON si se indica /C
  2909. param_unidad   DB    OFF               ; a ON si se indica A: o B:
  2910. param_13       DB    OFF               ; a ON si se indica /13
  2911.  
  2912. tipos_drv      LABEL BYTE
  2913. tipo_A         DW    -1                ; tipo de A:
  2914. tipo_B         DW    -1                ; y de B:
  2915.  
  2916. id_2m          DB    "CiriSOFT:2M:"    ; marcas de presencia de 2M
  2917. id_2m_tam      EQU   $-OFFSET id_2m
  2918. id_2mx         DB    "CiriSOFT:2MX:"
  2919. id_2mx_tam     EQU   $-OFFSET id_2mx
  2920. id_boot        DB    "2M-STV"
  2921. id_boot_tam    EQU   $-OFFSET id_boot
  2922.  
  2923. ERR_TIPOPC     EQU   1                 ; códigos de error
  2924. ERR_HAY2M      EQU   2
  2925. ERR_MALDRV     EQU   4
  2926. ERRSINTAX      EQU   8
  2927. MX64FULL       EQU  16
  2928.  
  2929. I40            EQU   1                 ; códigos de acción
  2930. BUFFERPLUS     EQU   2
  2931.  
  2932. offsets_ints   DW    3         ; número de vectores interceptados
  2933.                DB    15h       ; tabla de offsets de los vectores
  2934.                DW    ges_int15 ; de interrupción interceptados
  2935.                DB    2Fh
  2936.                DW    ges_int2F
  2937.                DB    40h
  2938.                DW    ges_int40
  2939.                DB    13h       ; INT 13h podría usarse
  2940.                DW    ges_int13
  2941.  
  2942. ptr_dev_info   DW    0, i360, i1200, i720, i1440, i2880
  2943.  
  2944. i360           DB    4, 0              ; sectores iguales / tipo 360K
  2945.                DW    0, 40             ; no detecta cambio / nº pistas
  2946.                DB    1                 ; tipo de soporte
  2947.                DW    512               ; BPB: bytes por sector
  2948.                DB    2                 ; BPB: sectores por cluster
  2949.                DW    1                 ; BPB: sectores reservados
  2950.                DB    2                 ; BPB: número de FATs
  2951.                DW    112               ; BPB: entradas en el raíz
  2952.                DW    720               ; BPB: nº total de sectores
  2953.                DB    0FDh              ; BPB: descriptor de medio
  2954.                DW    2                 ; BPB: sectores por FAT
  2955.                DW    9, 2              ; BPB: sectores pista / cabezas
  2956.                DB    14 DUP (0)        ; BPB: restantes campos
  2957. i1200          DB    4, 1              ; sectores iguales / tipo 1.2M
  2958.                DW    2, 80             ; detecta cambio / nº pistas
  2959.                DB    0                 ; tipo de soporte
  2960.                DW    512               ; BPB: bytes por sector
  2961.                DB    1                 ; BPB: sectores por cluster
  2962.                DW    1                 ; BPB: sectores reservados
  2963.                DB    2                 ; BPB: número de FATs
  2964.                DW    224               ; BPB: entradas en el raíz
  2965.                DW    2400              ; BPB: nº total de sectores
  2966.                DB    0F9h              ; BPB: descriptor de medio
  2967.                DW    7                 ; BPB: sectores por FAT
  2968.                DW    15, 2             ; BPB: sectores pista / cabezas
  2969.                DB    14 DUP (0)        ; BPB: restantes campos
  2970. i720           DB    4, 2              ; sectores iguales / tipo 720K
  2971.                DW    0, 80             ; no detecta cambio / nº pistas
  2972.                DB    0                 ; tipo de soporte
  2973.                DW    512               ; BPB: bytes por sector
  2974.                DB    2                 ; BPB: sectores por cluster
  2975.                DW    1                 ; BPB: sectores reservados
  2976.                DB    2                 ; BPB: número de FATs
  2977.                DW    112               ; BPB: entradas en el raíz
  2978.                DW    1440              ; BPB: nº total de sectores
  2979.                DB    0F9h              ; BPB: descriptor de medio
  2980.                DW    3                 ; BPB: sectores por FAT
  2981.                DW    9, 2              ; BPB: sectores pista / cabezas
  2982.                DB    14 DUP (0)        ; BPB: restantes campos
  2983. i1440          DB    4, 7              ; sectores iguales / tipo 1.44M
  2984.                DW    2, 80             ; detecta cambio / nº pistas
  2985.                DB    0                 ; tipo de soporte
  2986.                DW    512               ; BPB: bytes por sector
  2987.                DB    1                 ; BPB: sectores por cluster
  2988.                DW    1                 ; BPB: sectores reservados
  2989.                DB    2                 ; BPB: número de FATs
  2990.                DW    224               ; BPB: entradas en el raíz
  2991.                DW    2880              ; BPB: nº total de sectores
  2992.                DB    0F0h              ; BPB: descriptor de medio
  2993.                DW    9                 ; BPB: sectores por FAT
  2994.                DW    18, 2             ; BPB: sectores pista / cabezas
  2995.                DB    14 DUP (0)        ; BPB: restantes campos
  2996. i2880          DB    4, 9              ; sectores iguales / tipo 2.88M
  2997.                DW    2, 80             ; detecta cambio / nº pistas
  2998.                DB    0                 ; tipo de soporte
  2999.                DW    512               ; BPB: bytes por sector
  3000.                DB    2                 ; BPB: sectores por cluster
  3001.                DW    1                 ; BPB: sectores reservados
  3002.                DB    2                 ; BPB: número de FATs
  3003.                DW    224               ; BPB: entradas en el raíz
  3004.                DW    5760              ; BPB: nº total de sectores
  3005.                DB    0F0h              ; BPB: descriptor de medio
  3006.                DW    9                 ; BPB: sectores por FAT
  3007.                DW    36, 2             ; BPB: sectores pista / cabezas
  3008.                DB    14 DUP (0)        ; BPB: restantes campos
  3009.  
  3010. accion         DW    0
  3011. error          DW    0
  3012.  
  3013. ; ------------ Texto.
  3014.  
  3015.               IFNDEF  XT
  3016. info_ins_txt   DB    13,10,"2M-" ID "BIOS 1.3 controla las unidades de disquete."
  3017.                DB    13,10,"  Indique /? para obtener ayuda.",13,10,255
  3018.                DB    13,10,"2M-" ID "BIOS 1.3 drives diskette drives."
  3019.                DB    13,10,"  Execute with /? to obtain help.",13,10,0
  3020.               ELSE
  3021. info_ins_txt   DB    13,10,"2M-" ID "BIOS 1.3 controla las unidades de disquete."
  3022.                DB    13,10,"  Base de tiempos interna ajustada."
  3023.                DB    13,10,"  Indique /? para obtener ayuda.",13,10,255
  3024.                DB    13,10,"2M-" ID "BIOS 1.3 drives diskette drives"
  3025.                DB    13,10,"  Internal delay loop adjusted."
  3026.                DB    13,10,"  Execute with /? to obtain help.",13,10,0
  3027.               ENDIF
  3028.  
  3029. instalado_txt  DB    13,10,"2M-" ID "BIOS 1.3 instalado en",255
  3030.                DB    13,10,"2M-" ID "BIOS 1.3 installed on",0
  3031.  
  3032. a_txt          DB    " A:",0
  3033. b_txt          DB    " B:",0
  3034. ptr_txt_tipos  DW    d360, d1200, d720, d1440, d2880
  3035. d360           DB    "360K",0
  3036. d1200          DB    "1.2M",0
  3037. d720           DB    "720K",0
  3038. d1440          DB    "1.44M",0
  3039. d2880          DB    "2.88M",0
  3040. i40_txt        DB    "  [INT 40h]",13,10,0
  3041. i13_txt        DB    "  [INT 13h]",13,10,0
  3042.  
  3043. no_inst_txt    DB    13,10,"2M-" ID "BIOS 1.3 *NO* instalado.",13,10,255
  3044.                DB    13,10,"2M-" ID "BIOS 1.3 *NOT* installed.",13,10,0
  3045.  
  3046.               IFDEF  XT
  3047. mal_cpu_txt    DB    "  + Error: necesario equipo PC/XT. Utilice 2M-ABIOS en esta máquina.",13,10,255
  3048.                DB    "  + Error: needs a PC/XT system. Try 2M-ABIOS on this system.",13,10,0
  3049. hay2m_txt      DB    "  + Error: 2M-XBIOS debe instalarse *ANTES* de 2MX (y nunca en SuperBOOT).",13,10,255
  3050.                DB    "  + Error: 2M-XBIOS must be installed *BEFORE* 2MX (and never in SuperBOOT).",13,10,0
  3051.               ELSE
  3052. mal_cpu_txt    DB    "  + Error: necesario equipo AT ó superior. Utilice 2M-XBIOS en esta máquina.",13,10,255
  3053.                DB    "  + Error: needs AT or upper system. Try 2M-XBIOS on this system.",13,10,0
  3054. hay2m_txt      DB    "  + Error: 2M-ABIOS debe instalarse *ANTES* de 2M (y nunca en SuperBOOT).",13,10,255
  3055.                DB    "  + Error: 2M-ABIOS must be installed *BEFORE* 2M (and never in SuperBOOT).",13,10,0
  3056.               ENDIF
  3057.  
  3058. null_drv_txt   DB    "  + Utilice los parámetros para indicar expresamente el tipo de las unidades.",13,10,255
  3059.                DB    "  + Please use the switches to set the correct diskette drives type.",13,10,0
  3060.  
  3061. err_syntax_txt DB    "  + Error de sintaxis: ejecútelo desde el símbolo DOS para obtener ayuda.",13,10,255
  3062.                DB    "  + Syntax error: execute from DOS command line to obtain help.",13,10,0
  3063.  
  3064. err_mx64full   DB    "  + Error: Ya hay 64 programas residentes con la misma técnica.",13,10,7,255
  3065.                DB    "  + Error: There are already 64 TSR's with the same technique.",13,10,7,0
  3066.  
  3067. dma_cross_txt  DB    "    - Nota: El buffer de E/S cruzaba una frontera de DMA y fue ampliado.",13,10
  3068.                DB    "            Cambie la ubicación en memoria si desea ahorrar unos bytes.",13,10,255
  3069.                DB    "    - Note: I/O buffer has been extended because it crosses a DMA boundary.",13,10
  3070.                DB    "            Modify the memory location of 2M-" ID "BIOS to save a little memory.",13,10,0
  3071.  
  3072. limpia_txt     DB    13,"                                                                              ",13,0
  3073.  
  3074.               IFNDEF XT
  3075.  
  3076. info_txt       LABEL BYTE
  3077.                DB    13,10,10
  3078.                DB    "       2M-ABIOS 1.3  -  SOPORTE BIOS ACTUALIZADO PARA DISCOS ESTANDAR",13,10
  3079.                DB    "  (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
  3080.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3081.                DB    "         Sintaxis:  DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10
  3082.                DB    "    Algunos ordenadores poseen una BIOS antigua o con un diseño propio poco",13,10
  3083.                DB    "  compatible en el control de disco. En estas máquinas 2M y otros programas",13,10
  3084.                DB    "  de acceso a bajo nivel pueden fallar.  En dichos casos, conviene instalar",13,10
  3085.                DB    "  esta utilidad antes que 2M,  y en general que cualquier otro software que",13,10
  3086.                DB    "  acceda al subsistema de disco. Este programa es sólo para máquinas AT.",13,10,10
  3087.                DB    "    2M-ABIOS  actualiza el soporte de disco flexible a la última tecnología",13,10
  3088.                DB    "  de las BIOS AMI de 1993.  Si con 2M-ABIOS instalado 2M no opera de manera",13,10
  3089.                DB    "  totalmente correcta y en su máquina no está instalado algún otro software",13,10
  3090.                DB    "  de disco incompatible con 2M, entonces su ordenador no es 100% compatible",13,10
  3091.                DB    "  hardware con el estándar;  esto es particularmente cierto si con 2M-ABIOS",13,10
  3092.                DB    "  instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
  3093.                DB    "    Esta utilidad también es útil para añadir soporte de  1.44M  a máquinas",13,10
  3094.                DB    "  con BIOS antigua.  En estos casos, ignore la información sobre el tipo de",13,10
  3095.                DB    "  la unidad que pueda reportar dicha BIOS al arrancar.",13,10,10
  3096.                DB    "                                                          [PULSA UNA TECLA]",1
  3097.                DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10
  3098.                DB    "         Sintaxis:  DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10,10
  3099.                DB    "    Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
  3100.                DB    "  del eficaz código de control de disco de las BIOS AMI,  relevando así por",13,10
  3101.                DB    "  completo de esta tarea a la BIOS del sistema.  Generalmente no hará falta",13,10
  3102.                DB    "  indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).",13,10,10
  3103.                DB    '    Si al arrancar apareciera un mensaje como "Incorrect CMOS checksum", lo',13,10
  3104.                DB    "  que es poco probable, incluya la opción /C, reinicialice el PC y reajuste",13,10
  3105.                DB    "  la configuración entrando en el programa Setup del sistema. Así mismo, si",13,10
  3106.                DB    "  en algún momento dudara acerca de si  2M-ABIOS está controlando realmente",13,10
  3107.                DB    "  las unidades, puede utilizar la opción /13 para asegurarlo,  si bien esta",13,10
  3108.                DB    "  opción es poco recomendable cuando no es estrictamente necesaria.  AMI es",13,10
  3109.                DB    "  marca registrada de American Megatrends Inc.",13,10
  3110.                DB    255
  3111.                DB    13,10,10
  3112.                DB    "          2M-ABIOS 1.3  -  BIOS DISKETTE SUPPORT UPGRADE UTILITY",13,10
  3113.                DB    " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
  3114.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3115.                DB    "          Syntax:  DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10
  3116.                DB    "    Some computers have an old BIOS or a BIOS built with a peculiar design,",13,10
  3117.                DB    "  few compatible in disk operation. In those systems 2M and other low-level",13,10
  3118.                DB    "  software can fail.  In this cases, you can install 2M-ABIOS before 2M and",13,10
  3119.                DB    "  before any other  TSR  disk software.  This program is only for use on AT",13,10
  3120.                DB    "  computer systems.",13,10,10
  3121.                DB    "    2M-ABIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
  3122.                DB    "  If 2M-ABIOS  is  installed  and  there  isn't  any  other  disk  software",13,10
  3123.                DB    "  incompatible with 2M installed,  but  2M doesn't work full  correctly  on",13,10
  3124.                DB    "  your  computer,  this  probably  means  that  your computer is  not  100%",13,10
  3125.                DB    "  hardware compatible with the AT standard.  This is specially true if just",13,10
  3126.                DB    "  2M-ABIOS is installed and DOS standard diskettes don't work.",13,10,10
  3127.                DB    "    This utility is also useful to  add  1.44M  support to systems with old",13,10
  3128.                DB    "  designed BIOS.  In this cases, you must ignore the information about disk",13,10
  3129.                DB    "  type reported by such BIOS while booting.",13,10,10
  3130.                DB    "                                                            [PRESS ANY KEY]",1
  3131.                DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"               ",13,10
  3132.                DB    "          Syntax:  DEVICE=2M-ABIOS.EXE [A:tipo] [B:tipo] [/C] [/13]",13,10,10,10
  3133.                DB    "    This program takes 3.4-4.2 Kb of RAM,  and provides a full emulation of",13,10
  3134.                DB    "  the effective disk control management of AMI BIOS,  absolutely overriding",13,10
  3135.                DB    "  your native BIOS in this job.  You won't usually need to select the drive",13,10
  3136.                DB    "  type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).",13,10,10
  3137.                DB    '     If during system boot a "Incorrect CMOS checksum" message appears, you',13,10
  3138.                DB    "  must set the /C switch, reboot the system and run the Setup program (this",13,10
  3139.                DB    "  is a very unusual problem).  Also,  if you realise that  2M-ABIOS  is not",13,10
  3140.                DB    "  driving your disks, you can set the /13 switch to avoid this problem; but",13,10
  3141.                DB    "  this switch is only recomended when it is completely necessary.  AMI is a",13,10
  3142.                DB    "  registered trademark of American Megatrends Inc.",13,10
  3143.                DB    0
  3144.  
  3145.               ELSE
  3146.  
  3147. info_txt       LABEL BYTE
  3148.                DB    13,10,10
  3149.                DB    "       2M-XBIOS 1.3  -  SOPORTE BIOS ACTUALIZADO PARA DISCOS ESTANDAR",13,10
  3150.                DB    "  (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática",13,10
  3151.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3152.                DB    "            Sintaxis:  DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10
  3153.                DB    "    La mayoría de PC/XT tiene una BIOS antigua sin soporte de alta densidad",13,10
  3154.                DB    "  aunque admiten una controladora de AT de alta densidad. Para trabajar con",13,10
  3155.                DB    "  unidades de alta densidad necesitan 2M-XBIOS.  Además, 2MX suele requerir",13,10
  3156.                DB    "  que esté instalado 2M-XBIOS,  que debería ser cargado antes que cualquier",13,10
  3157.                DB    "  otro software de disco. Este programa es sólo para máquinas PC/XT.",13,10,10
  3158.                DB    "    2M-XBIOS  actualiza el soporte de disco flexible a la última tecnología",13,10
  3159.                DB    "  de las BIOS AMI de 1993. Si con 2M-XBIOS instalado 2MX no opera de manera",13,10
  3160.                DB    "  totalmente correcta y en su máquina no está instalado algún otro software",13,10
  3161.                DB    "  de disco incompatible con 2MX entonces su ordenador no es 100% compatible",13,10
  3162.                DB    "  hardware con el estándar;  esto es particularmente cierto si con 2M-XBIOS",13,10
  3163.                DB    "  instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
  3164.                DB    "     Si en algún momento dudara acerca de si  2M-XBIOS está controlando las",13,10
  3165.                DB    "  unidades realmente, puede utilizar la opción /13 para asegurarlo, si bien",13,10
  3166.                DB    "  esta opción es poco recomendable cuando no es estrictamente necesaria.",13,10,10
  3167.                DB    "                                                          [PULSA UNA TECLA]",1
  3168.                DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"                 ",13,10
  3169.                DB    "            Sintaxis:  DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10,10
  3170.                DB    "    Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
  3171.                DB    "  del eficaz código de control de disco de las BIOS AMI,  relevando así por",13,10
  3172.                DB    "  completo de esta tarea a la BIOS del sistema. Generalmente será necesario",13,10
  3173.                DB    "  indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI",13,10
  3174.                DB    "  es marca registrada de American Megatrends Inc.",13,10
  3175.                DB    255
  3176.                DB    13,10,10
  3177.                DB    "          2M-XBIOS 1.3  -  BIOS DISKETTE SUPPORT UPGRADE UTILITY",13,10
  3178.                DB    " (C) 1994-1995 Ciriaco García de Celis - Grupo Universitario de Informática.",13,10
  3179.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3180.                DB    "             Syntax:  DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10
  3181.                DB    "    Most  PC/XT  systems have an old BIOS with no high density support, but",13,10
  3182.                DB    "  they can be equiped with an AT high density disk controller. To work with",13,10
  3183.                DB    "  high density drives they need 2M-XBIOS.  Also,  2MX  usually requires the",13,10
  3184.                DB    "  previous installation of 2M-XBIOS:  you  must install it before any other",13,10
  3185.                DB    "  TSR disk software. This program is only for use on PC/XT systems.",13,10,10
  3186.                DB    "    2M-XBIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
  3187.                DB    "  If 2M-XBIOS  is  installed  and  there  isn't  any  other  disk  software",13,10
  3188.                DB    "  incompatible with 2MX installed, but 2MX doesn't work full  correctly  on",13,10
  3189.                DB    "  your  computer,  this  probably  means  that  your computer is  not  100%",13,10
  3190.                DB    "  hardware compatible with the XT standard.  This is specially true if just",13,10
  3191.                DB    "  2M-XBIOS is installed and DOS standard diskettes don't work.",13,10,10
  3192.                DB    "    If at any moment you realise that  2M-XBIOS  is not really driving your",13,10
  3193.                DB    "  disks, you can set the /13 switch to avoid this problem;  but this switch",13,10
  3194.                DB    "  is only recomended when it is completely necessary.",13,10,10
  3195.                DB    "                                                            [PRESS ANY KEY]",1
  3196.                DB    8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,"               ",13,10
  3197.                DB    "             Syntax:  DEVICE=2M-XBIOS.EXE [A:tipo] [B:tipo] [/13]",13,10,10,10
  3198.                DB    "    This program takes 3.4-4.2 Kb of RAM,  and provides a full emulation of",13,10
  3199.                DB    "  the effective disk control management of AMI BIOS,  absolutely overriding",13,10
  3200.                DB    "  your native BIOS in this job. You will usually need to select  the  drive",13,10
  3201.                DB    "  type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).  AMI is a",13,10
  3202.                DB    "  registered trademark of American Megatrends Inc.",13,10
  3203.                DB    0
  3204.  
  3205.               ENDIF
  3206.  
  3207. buffer_aux     DB    64 DUP (0)   ; buffer para alguna función del DOS
  3208.  
  3209. _PRINCIPAL     ENDS
  3210.  
  3211. _PILA          SEGMENT STACK 'STACK'
  3212.                DB    1024 DUP (?)      ; 1 Kb de pila es suficiente
  3213. _PILA          ENDS
  3214.  
  3215.                END   inicio
  3216.